@lobehub/lobehub 2.0.0-next.343 → 2.0.0-next.345

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 (169) hide show
  1. package/.cursor/rules/i18n.mdc +1 -1
  2. package/.cursor/rules/modal-imperative.mdc +162 -0
  3. package/.cursor/rules/rules-index.mdc +1 -0
  4. package/.env.example +0 -14
  5. package/.eslintrc.js +8 -1
  6. package/CHANGELOG.md +66 -0
  7. package/Dockerfile +3 -13
  8. package/README.md +3 -5
  9. package/README.zh-CN.md +3 -5
  10. package/changelog/v1.json +24 -0
  11. package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +11 -42
  12. package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +10 -41
  13. package/e2e/src/support/webServer.ts +2 -0
  14. package/locales/ar/error.json +0 -4
  15. package/locales/bg-BG/error.json +0 -4
  16. package/locales/de-DE/error.json +0 -4
  17. package/locales/en-US/error.json +0 -4
  18. package/locales/es-ES/error.json +0 -4
  19. package/locales/fa-IR/error.json +0 -4
  20. package/locales/fr-FR/error.json +0 -4
  21. package/locales/it-IT/error.json +0 -4
  22. package/locales/ja-JP/error.json +0 -4
  23. package/locales/ko-KR/error.json +0 -4
  24. package/locales/nl-NL/error.json +0 -4
  25. package/locales/pl-PL/error.json +0 -4
  26. package/locales/pt-BR/error.json +0 -4
  27. package/locales/ru-RU/error.json +0 -4
  28. package/locales/tr-TR/error.json +0 -4
  29. package/locales/vi-VN/error.json +0 -4
  30. package/locales/zh-CN/error.json +0 -4
  31. package/locales/zh-TW/error.json +0 -4
  32. package/package.json +7 -9
  33. package/packages/builtin-agents/package.json +2 -0
  34. package/packages/builtin-agents/src/agents/agent-builder/index.ts +4 -2
  35. package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +4 -2
  36. package/packages/builtin-agents/src/agents/page-agent/index.ts +5 -2
  37. package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +161 -12
  38. package/packages/context-engine/src/engine/messages/MessagesEngine.ts +9 -9
  39. package/packages/context-engine/src/providers/GroupContextInjector.ts +19 -33
  40. package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +79 -43
  41. package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +5 -15
  42. package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +24 -3
  43. package/packages/model-bank/src/modelProviders/comfyui.ts +0 -1
  44. package/packages/model-bank/src/modelProviders/fal.ts +0 -1
  45. package/packages/types/src/fetch.ts +1 -2
  46. package/packages/utils/src/server/__tests__/auth.test.ts +0 -47
  47. package/packages/utils/src/server/auth.ts +1 -9
  48. package/scripts/_shared/checkDeprecatedClerkEnv.js +42 -0
  49. package/scripts/changelogWorkflow/buildStaticChangelog.ts +2 -1
  50. package/scripts/clerk-to-betterauth/_internal/types.ts +53 -20
  51. package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +43 -36
  52. package/scripts/countEnWord.ts +1 -1
  53. package/scripts/electronWorkflow/modifiers/appCode.mts +2 -131
  54. package/scripts/i18nWorkflow/protectedPatterns.ts +1 -2
  55. package/scripts/prebuild.mts +10 -8
  56. package/scripts/serverLauncher/startServer.js +23 -5
  57. package/src/app/(backend)/middleware/auth/index.test.ts +8 -4
  58. package/src/app/(backend)/middleware/auth/index.ts +0 -15
  59. package/src/app/(backend)/middleware/auth/utils.test.ts +0 -28
  60. package/src/app/(backend)/middleware/auth/utils.ts +2 -17
  61. package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +3 -51
  62. package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -4
  63. package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +7 -6
  64. package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -16
  65. package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/index.tsx +1 -1
  66. package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +13 -13
  67. package/src/app/[variants]/(main)/home/features/RecentPage/Item.tsx +2 -2
  68. package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
  69. package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -2
  70. package/src/app/[variants]/(main)/settings/security/index.tsx +1 -22
  71. package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +12 -14
  72. package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +8 -14
  73. package/src/app/[variants]/(main)/settings/skill/index.tsx +7 -5
  74. package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +2 -35
  75. package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
  76. package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -2
  77. package/src/app/[variants]/(mobile)/me/profile/features/Category.tsx +3 -13
  78. package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +2 -3
  79. package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
  80. package/src/app/[variants]/share/t/[id]/index.tsx +1 -1
  81. package/src/app/robots.tsx +1 -1
  82. package/src/envs/auth.ts +2 -27
  83. package/src/envs/llm.ts +2 -2
  84. package/src/features/AgentSetting/AgentPlugin/index.tsx +9 -12
  85. package/src/features/ChatInput/ActionBar/Tools/index.tsx +7 -5
  86. package/src/features/ChatMiniMap/utils.ts +1 -1
  87. package/src/features/CommandMenu/SearchResults.tsx +1 -1
  88. package/src/features/Conversation/ChatList/components/AutoScroll/DebugInspector.tsx +166 -0
  89. package/src/features/Conversation/ChatList/components/AutoScroll/index.tsx +86 -0
  90. package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +11 -17
  91. package/src/features/Conversation/Messages/AgentCouncil/components/AutoScrollShadow.tsx +25 -14
  92. package/src/features/Conversation/Messages/AgentCouncil/components/CouncilMember.tsx +1 -1
  93. package/src/features/IntegrationDetailModal/IntegrationDetailContent.tsx +305 -0
  94. package/src/features/IntegrationDetailModal/index.tsx +21 -283
  95. package/src/features/MCPPluginDetail/Deployment/index.tsx +1 -1
  96. package/src/features/MCPPluginDetail/Schema/Prompts.tsx +1 -1
  97. package/src/features/MCPPluginDetail/Schema/Tools.tsx +1 -1
  98. package/src/features/ProfileEditor/AgentTool.tsx +14 -20
  99. package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/NoteFileItem.tsx +1 -1
  100. package/src/features/SkillStore/LobeHubList/index.tsx +50 -87
  101. package/src/features/SkillStore/Search/index.tsx +1 -1
  102. package/src/features/SkillStore/{Content.tsx → SkillStoreContent.tsx} +3 -8
  103. package/src/features/SkillStore/index.tsx +15 -33
  104. package/src/features/User/UserPanel/PanelContent.tsx +0 -8
  105. package/src/features/User/__tests__/PanelContent.test.tsx +1 -35
  106. package/src/features/User/__tests__/UserAvatar.test.tsx +30 -57
  107. package/src/features/User/__tests__/useMenu.test.tsx +2 -43
  108. package/src/layout/AuthProvider/index.tsx +0 -5
  109. package/src/libs/next/config/define-config.ts +6 -0
  110. package/src/libs/next/proxy/createRouteMatcher.test.ts +121 -0
  111. package/src/libs/next/proxy/createRouteMatcher.ts +18 -0
  112. package/src/libs/next/proxy/define-config.ts +4 -53
  113. package/src/libs/next-auth/adapter/index.ts +1 -2
  114. package/src/libs/oidc-provider/provider.test.ts +5 -316
  115. package/src/libs/trpc/lambda/context.test.ts +0 -13
  116. package/src/libs/trpc/lambda/context.ts +3 -22
  117. package/src/libs/trpc/middleware/userAuth.ts +2 -4
  118. package/src/libs/trusted-client/getSessionUser.ts +2 -17
  119. package/src/locales/default/error.ts +0 -6
  120. package/src/locales/default/index.ts +0 -2
  121. package/src/proxy.ts +0 -1
  122. package/src/server/routers/lambda/__tests__/user.test.ts +0 -71
  123. package/src/server/routers/lambda/user.ts +6 -63
  124. package/src/server/services/changelog/index.test.ts +3 -2
  125. package/src/server/services/changelog/index.ts +1 -1
  126. package/src/server/services/user/index.ts +0 -83
  127. package/src/services/chat/index.ts +1 -2
  128. package/src/services/chat/mecha/agentConfigResolver.test.ts +43 -0
  129. package/src/services/chat/mecha/agentConfigResolver.ts +3 -1
  130. package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +58 -14
  131. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +10 -2
  132. package/src/store/user/slices/auth/action.test.ts +1 -81
  133. package/src/store/user/slices/auth/action.ts +3 -28
  134. package/src/store/user/slices/auth/initialState.ts +1 -18
  135. package/src/store/user/slices/auth/selectors.test.ts +2 -127
  136. package/src/store/user/slices/auth/selectors.ts +1 -21
  137. package/src/utils/errorResponse.ts +1 -4
  138. package/src/utils/markdownToTxt.ts +20 -0
  139. package/locales/ar/clerk.json +0 -545
  140. package/locales/bg-BG/clerk.json +0 -545
  141. package/locales/de-DE/clerk.json +0 -545
  142. package/locales/en-US/clerk.json +0 -545
  143. package/locales/es-ES/clerk.json +0 -545
  144. package/locales/fa-IR/clerk.json +0 -545
  145. package/locales/fr-FR/clerk.json +0 -545
  146. package/locales/it-IT/clerk.json +0 -545
  147. package/locales/ja-JP/clerk.json +0 -545
  148. package/locales/ko-KR/clerk.json +0 -545
  149. package/locales/nl-NL/clerk.json +0 -545
  150. package/locales/pl-PL/clerk.json +0 -545
  151. package/locales/pt-BR/clerk.json +0 -545
  152. package/locales/ru-RU/clerk.json +0 -545
  153. package/locales/tr-TR/clerk.json +0 -545
  154. package/locales/vi-VN/clerk.json +0 -545
  155. package/locales/zh-CN/clerk.json +0 -545
  156. package/locales/zh-TW/clerk.json +0 -545
  157. package/src/app/(backend)/api/webhooks/clerk/__tests__/fixtures/createUser.json +0 -73
  158. package/src/app/(backend)/api/webhooks/clerk/route.ts +0 -95
  159. package/src/app/(backend)/api/webhooks/clerk/validateRequest.ts +0 -22
  160. package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +0 -27
  161. package/src/app/[variants]/(main)/settings/security/features/ClerkProfile.tsx +0 -67
  162. package/src/features/Conversation/ChatList/components/AutoScroll.tsx +0 -25
  163. package/src/layout/AuthProvider/Clerk/UserUpdater.tsx +0 -40
  164. package/src/layout/AuthProvider/Clerk/index.tsx +0 -54
  165. package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -133
  166. package/src/libs/clerk-auth/index.test.ts +0 -216
  167. package/src/libs/clerk-auth/index.ts +0 -80
  168. package/src/locales/default/clerk.ts +0 -677
  169. package/src/server/services/user/index.test.ts +0 -220
@@ -11,7 +11,6 @@
11
11
  * Files to ignore at file level (won't be scanned at all)
12
12
  */
13
13
  export const IGNORED_FILES = [
14
- 'clerk.ts', // Clerk third-party library translations
15
14
  'providers.ts', // Dynamically generated from DEFAULT_MODEL_PROVIDER_LIST
16
15
  'models.ts', // Dynamically generated from LOBE_DEFAULT_MODEL_LIST
17
16
  'auth.ts', // Auth-related dynamic keys
@@ -77,7 +76,7 @@ export const PROTECTED_KEY_PATTERNS = [
77
76
  * How to use:
78
77
  *
79
78
  * 1. IGNORED_FILES - Files to completely skip during analysis:
80
- * Add filename with .ts extension (e.g., 'clerk.ts')
79
+ * Add filename with .ts extension (e.g., 'auth.ts')
81
80
  * These files won't be scanned at all
82
81
  *
83
82
  * 2. PROTECTED_KEY_PATTERNS - Namespace/patterns to protect:
@@ -1,4 +1,5 @@
1
1
  import { execSync } from 'node:child_process';
2
+ import { createRequire } from 'node:module';
2
3
  import * as dotenv from 'dotenv';
3
4
  import dotenvExpand from 'dotenv-expand';
4
5
  import { existsSync } from 'node:fs';
@@ -6,6 +7,10 @@ import { rm } from 'node:fs/promises';
6
7
  import path from 'node:path';
7
8
  import { fileURLToPath } from 'node:url';
8
9
 
10
+ // Use createRequire for CommonJS module compatibility
11
+ const require = createRequire(import.meta.url);
12
+ const { checkDeprecatedClerkEnv } = require('./_shared/checkDeprecatedClerkEnv.js');
13
+
9
14
  const isDesktop = process.env.NEXT_PUBLIC_IS_DESKTOP_APP === '1';
10
15
  const isBundleAnalyzer = process.env.ANALYZE === 'true' && process.env.CI === 'true';
11
16
 
@@ -17,13 +22,9 @@ if (isDesktop) {
17
22
  }
18
23
 
19
24
  // Auth flags - use process.env directly for build-time dead code elimination
20
- const enableClerk =
21
- process.env.NEXT_PUBLIC_ENABLE_CLERK_AUTH === '1'
22
- ? true
23
- : !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
24
- const enableBetterAuth = process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1';
25
+ // Better Auth is the default auth solution when NextAuth is not explicitly enabled
25
26
  const enableNextAuth = process.env.NEXT_PUBLIC_ENABLE_NEXT_AUTH === '1';
26
- const enableAuth = enableClerk || enableBetterAuth || enableNextAuth || false;
27
+ const enableBetterAuth = !enableNextAuth;
27
28
 
28
29
  const getCommandVersion = (command: string): string | null => {
29
30
  try {
@@ -62,10 +63,8 @@ const printEnvInfo = () => {
62
63
 
63
64
  // Auth flags
64
65
  console.log('\n Auth Flags:');
65
- console.log(` enableClerk: ${enableClerk}`);
66
66
  console.log(` enableBetterAuth: ${enableBetterAuth}`);
67
67
  console.log(` enableNextAuth: ${enableNextAuth}`);
68
- console.log(` enableAuth: ${enableAuth}`);
69
68
 
70
69
  console.log('─'.repeat(50));
71
70
  };
@@ -161,6 +160,9 @@ export const runPrebuild = async (targetDir: string = 'src') => {
161
160
  const isMainModule = process.argv[1] === fileURLToPath(import.meta.url);
162
161
 
163
162
  if (isMainModule) {
163
+ // Check for deprecated Clerk env vars first - fail fast if found
164
+ checkDeprecatedClerkEnv();
165
+
164
166
  printEnvInfo();
165
167
  // 执行删除操作
166
168
  console.log('\nStarting prebuild cleanup...');
@@ -1,6 +1,17 @@
1
1
  const dns = require('node:dns').promises;
2
2
  const fs = require('node:fs').promises;
3
+ const path = require('node:path');
3
4
  const { spawn } = require('node:child_process');
5
+ const { existsSync } = require('node:fs');
6
+
7
+ // Resolve shared module path for both local dev and Docker environments
8
+ // Local: scripts/serverLauncher/startServer.js -> scripts/_shared/...
9
+ // Docker: /app/startServer.js -> /app/scripts/_shared/...
10
+ const localPath = path.join(__dirname, '..', '_shared', 'checkDeprecatedClerkEnv.js');
11
+ const dockerPath = '/app/scripts/_shared/checkDeprecatedClerkEnv.js';
12
+ const sharedModulePath = existsSync(localPath) ? localPath : dockerPath;
13
+
14
+ const { checkDeprecatedClerkEnv } = require(sharedModulePath);
4
15
 
5
16
  // Set file paths
6
17
  const DB_MIGRATION_SCRIPT_PATH = '/app/docker.cjs';
@@ -9,8 +20,7 @@ const PROXYCHAINS_CONF_PATH = '/etc/proxychains4.conf';
9
20
 
10
21
  // Function to check if a string is a valid IP address
11
22
  const isValidIP = (ip, version = 4) => {
12
- const ipv4Regex =
13
- /^(25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3}$/;
23
+ const ipv4Regex = /^(25[0-5]|2[0-4]\d|[01]?\d{1,2})(\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})){3}$/;
14
24
  const ipv6Regex =
15
25
  /^(([\da-f]{1,4}:){7}[\da-f]{1,4}|([\da-f]{1,4}:){1,7}:|([\da-f]{1,4}:){1,6}:[\da-f]{1,4}|([\da-f]{1,4}:){1,5}(:[\da-f]{1,4}){1,2}|([\da-f]{1,4}:){1,4}(:[\da-f]{1,4}){1,3}|([\da-f]{1,4}:){1,3}(:[\da-f]{1,4}){1,4}|([\da-f]{1,4}:){1,2}(:[\da-f]{1,4}){1,5}|[\da-f]{1,4}:((:[\da-f]{1,4}){1,6})|:((:[\da-f]{1,4}){1,7}|:)|fe80:(:[\da-f]{0,4}){0,4}%[\da-z]+|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)|([\da-f]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d)\.){3}(25[0-5]|(2[0-4]|1{0,1}\d){0,1}\d))$/;
16
26
 
@@ -74,10 +84,13 @@ const runProxyChainsConfGenerator = async (url) => {
74
84
 
75
85
  let ip = isValidIP(host, 4) ? host : await resolveHostIP(host, 4);
76
86
 
77
- const proxyDNSConfig = process.env.ENABLE_PROXY_DNS === '1' ? `
87
+ const proxyDNSConfig =
88
+ process.env.ENABLE_PROXY_DNS === '1'
89
+ ? `
78
90
  proxy_dns
79
91
  remote_dns_subnet 224
80
- `.trim() : '';
92
+ `.trim()
93
+ : '';
81
94
 
82
95
  const configContent = `
83
96
  localnet 127.0.0.0/8
@@ -91,7 +104,9 @@ tcp_connect_time_out 8000
91
104
  tcp_read_time_out 15000
92
105
  [ProxyList]
93
106
  ${protocol} ${ip} ${port} ${user} ${pass}
94
- `.replace(/\n{2,}/g, '\n').trim();
107
+ `
108
+ .replaceAll(/\n{2,}/g, '\n')
109
+ .trim();
95
110
 
96
111
  await fs.writeFile(PROXYCHAINS_CONF_PATH, configContent);
97
112
  console.log(`✅ ProxyChains: All outgoing traffic routed via ${url}.`);
@@ -124,6 +139,9 @@ const runServer = async () => {
124
139
 
125
140
  // Main execution block
126
141
  (async () => {
142
+ // Check for deprecated Clerk env vars first - fail fast if found
143
+ checkDeprecatedClerkEnv({ action: 'restart' });
144
+
127
145
  console.log('🌐 DNS Server:', dns.getServers());
128
146
  console.log('-------------------------------------');
129
147
 
@@ -8,10 +8,6 @@ import { createErrorResponse } from '@/utils/errorResponse';
8
8
  import { RequestHandler, checkAuth } from './index';
9
9
  import { checkAuthMethod } from './utils';
10
10
 
11
- vi.mock('@clerk/nextjs/server', () => ({
12
- getAuth: vi.fn(),
13
- }));
14
-
15
11
  vi.mock('@/utils/errorResponse', () => ({
16
12
  createErrorResponse: vi.fn(),
17
13
  }));
@@ -24,6 +20,14 @@ vi.mock('@lobechat/utils/server', () => ({
24
20
  getXorPayload: vi.fn(),
25
21
  }));
26
22
 
23
+ vi.mock('@/envs/auth', async (importOriginal) => {
24
+ const actual = await importOriginal<typeof import('@/envs/auth')>();
25
+ return {
26
+ ...actual,
27
+ enableBetterAuth: false,
28
+ };
29
+ });
30
+
27
31
  describe('checkAuth', () => {
28
32
  const mockHandler: RequestHandler = vi.fn();
29
33
  const mockRequest = new Request('https://example.com');
@@ -1,4 +1,3 @@
1
- import { type AuthObject } from '@clerk/backend';
2
1
  import {
3
2
  AgentRuntimeError,
4
3
  type ChatCompletionErrorPayload,
@@ -6,7 +5,6 @@ import {
6
5
  } from '@lobechat/model-runtime';
7
6
  import { ChatErrorType, type ClientSecretPayload } from '@lobechat/types';
8
7
  import { getXorPayload } from '@lobechat/utils/server';
9
- import { type NextRequest } from 'next/server';
10
8
 
11
9
  import { getServerDB } from '@/database/core/db-adaptor';
12
10
  import { type LobeChatDatabase } from '@/database/type';
@@ -15,9 +13,7 @@ import {
15
13
  LOBE_CHAT_OIDC_AUTH_HEADER,
16
14
  OAUTH_AUTHORIZED,
17
15
  enableBetterAuth,
18
- enableClerk,
19
16
  } from '@/envs/auth';
20
- import { ClerkAuth } from '@/libs/clerk-auth';
21
17
  import { validateOIDCJWT } from '@/libs/oidc-provider/jwt';
22
18
  import { createErrorResponse } from '@/utils/errorResponse';
23
19
 
@@ -77,16 +73,6 @@ export const checkAuth =
77
73
 
78
74
  if (!authorization) throw AgentRuntimeError.createError(ChatErrorType.Unauthorized);
79
75
 
80
- // check the Auth With payload and clerk auth
81
- let clerkAuth = {} as AuthObject;
82
-
83
- // TODO: V2 完整移除 client 模式下的 clerk 集成代码
84
- if (enableClerk) {
85
- const auth = new ClerkAuth();
86
- const data = auth.getAuthFromRequest(req as NextRequest);
87
- clerkAuth = data.clerkAuth;
88
- }
89
-
90
76
  jwtPayload = getXorPayload(authorization);
91
77
 
92
78
  const oidcAuthorization = req.headers.get(LOBE_CHAT_OIDC_AUTH_HEADER);
@@ -106,7 +92,6 @@ export const checkAuth =
106
92
  checkAuthMethod({
107
93
  apiKey: jwtPayload.apiKey,
108
94
  betterAuthAuthorized,
109
- clerkAuth,
110
95
  nextAuthAuthorized: oauthAuthorized,
111
96
  });
112
97
  } catch (e) {
@@ -1,9 +1,7 @@
1
- import { type AuthObject } from '@clerk/backend';
2
1
  import { beforeEach, describe, expect, it, vi } from 'vitest';
3
2
 
4
3
  import { checkAuthMethod } from './utils';
5
4
 
6
- let enableClerkMock = false;
7
5
  let enableNextAuthMock = false;
8
6
  let enableBetterAuthMock = false;
9
7
 
@@ -12,9 +10,6 @@ vi.mock('@/envs/auth', async (importOriginal) => {
12
10
 
13
11
  return {
14
12
  ...(data as any),
15
- get enableClerk() {
16
- return enableClerkMock;
17
- },
18
13
  get enableBetterAuth() {
19
14
  return enableBetterAuthMock;
20
15
  },
@@ -29,29 +24,6 @@ describe('checkAuthMethod', () => {
29
24
  vi.clearAllMocks();
30
25
  });
31
26
 
32
- it('should pass with valid Clerk auth', () => {
33
- enableClerkMock = true;
34
- expect(() =>
35
- checkAuthMethod({
36
- clerkAuth: { userId: 'someUserId' } as AuthObject,
37
- }),
38
- ).not.toThrow();
39
-
40
- enableClerkMock = false;
41
- });
42
-
43
- it('should throw error with invalid Clerk auth', () => {
44
- enableClerkMock = true;
45
- try {
46
- checkAuthMethod({
47
- clerkAuth: {} as any,
48
- });
49
- } catch (e) {
50
- expect(e).toEqual({ errorType: 'InvalidClerkUser' });
51
- }
52
- enableClerkMock = false;
53
- });
54
-
55
27
  it('should pass with valid Next auth', () => {
56
28
  enableNextAuthMock = true;
57
29
  expect(() =>
@@ -1,13 +1,8 @@
1
- import { type AuthObject } from '@clerk/backend';
2
- import { AgentRuntimeError } from '@lobechat/model-runtime';
3
- import { ChatErrorType } from '@lobechat/types';
4
-
5
- import { enableBetterAuth, enableClerk, enableNextAuth } from '@/envs/auth';
1
+ import { enableBetterAuth, enableNextAuth } from '@/envs/auth';
6
2
 
7
3
  interface CheckAuthParams {
8
4
  apiKey?: string;
9
5
  betterAuthAuthorized?: boolean;
10
- clerkAuth?: AuthObject;
11
6
  nextAuthAuthorized?: boolean;
12
7
  }
13
8
  /**
@@ -16,20 +11,10 @@ interface CheckAuthParams {
16
11
  * @param {CheckAuthParams} params - Authentication parameters extracted from headers.
17
12
  * @param {string} [params.apiKey] - The user API key.
18
13
  * @param {boolean} [params.betterAuthAuthorized] - Whether the Better Auth session exists.
19
- * @param {AuthObject} [params.clerkAuth] - Clerk authentication payload from middleware.
20
14
  * @param {boolean} [params.nextAuthAuthorized] - Whether the OAuth 2 header is provided.
21
- * @throws {AgentRuntimeError} If authentication fails.
22
15
  */
23
16
  export const checkAuthMethod = (params: CheckAuthParams) => {
24
- const { apiKey, betterAuthAuthorized, nextAuthAuthorized, clerkAuth } = params;
25
- // clerk auth handler
26
- if (enableClerk) {
27
- // if there is no userId, means the use is not login, just throw error
28
- if (!(clerkAuth as any)?.userId)
29
- throw AgentRuntimeError.createError(ChatErrorType.InvalidClerkUser);
30
- // if the user is login, just return
31
- else return;
32
- }
17
+ const { apiKey, betterAuthAuthorized, nextAuthAuthorized } = params;
33
18
 
34
19
  // if better auth session exists
35
20
  if (enableBetterAuth && betterAuthAuthorized) return;
@@ -1,5 +1,4 @@
1
1
  // @vitest-environment node
2
- import { getAuth } from '@clerk/nextjs/server';
3
2
  import { LobeRuntimeAI, ModelRuntime } from '@lobechat/model-runtime';
4
3
  import { ChatErrorType } from '@lobechat/types';
5
4
  import { getXorPayload } from '@lobechat/utils/server';
@@ -11,10 +10,6 @@ import { initModelRuntimeFromDB } from '@/server/modules/ModelRuntime';
11
10
 
12
11
  import { POST } from './route';
13
12
 
14
- vi.mock('@clerk/nextjs/server', () => ({
15
- getAuth: vi.fn(),
16
- }));
17
-
18
13
  vi.mock('@/app/(backend)/middleware/auth/utils', () => ({
19
14
  checkAuthMethod: vi.fn(),
20
15
  }));
@@ -28,17 +23,11 @@ vi.mock('@/server/modules/ModelRuntime', () => ({
28
23
  createTraceOptions: vi.fn().mockReturnValue({}),
29
24
  }));
30
25
 
31
- // Use vi.hoisted to ensure mockState is initialized before mocks are set up
32
- const mockState = vi.hoisted(() => ({ enableClerk: false }));
33
-
34
- // 模拟 @/const/auth 模块
35
26
  vi.mock('@/envs/auth', async (importOriginal) => {
36
- const modules = await importOriginal();
27
+ const actual = await importOriginal<typeof import('@/envs/auth')>();
37
28
  return {
38
- ...(modules as any),
39
- get enableClerk() {
40
- return mockState.enableClerk;
41
- },
29
+ ...actual,
30
+ enableBetterAuth: false,
42
31
  };
43
32
  });
44
33
 
@@ -58,7 +47,6 @@ beforeEach(() => {
58
47
  afterEach(() => {
59
48
  // 清除模拟调用历史
60
49
  vi.clearAllMocks();
61
- mockState.enableClerk = false;
62
50
  });
63
51
 
64
52
  describe('POST handler', () => {
@@ -108,42 +96,6 @@ describe('POST handler', () => {
108
96
  });
109
97
  });
110
98
 
111
- it('should have pass clerk Auth when enable clerk', async () => {
112
- mockState.enableClerk = true;
113
-
114
- vi.mocked(getXorPayload).mockReturnValueOnce({
115
- apiKey: 'test-api-key',
116
- azureApiVersion: 'v1',
117
- });
118
-
119
- const mockParams = Promise.resolve({ provider: 'test-provider' });
120
- vi.mocked(getAuth).mockReturnValue({} as any);
121
- vi.mocked(checkAuthMethod).mockReset();
122
-
123
- const mockRuntime: LobeRuntimeAI = { baseURL: 'abc', chat: vi.fn() };
124
-
125
- // Mock initModelRuntimeFromDB
126
- vi.mocked(initModelRuntimeFromDB).mockResolvedValue(new ModelRuntime(mockRuntime));
127
-
128
- const request = new Request(new URL('https://test.com'), {
129
- method: 'POST',
130
- body: JSON.stringify({ model: 'test-model' }),
131
- headers: {
132
- [LOBE_CHAT_AUTH_HEADER]: 'some-valid-token',
133
- [OAUTH_AUTHORIZED]: '1',
134
- },
135
- });
136
-
137
- await POST(request, { params: mockParams });
138
-
139
- expect(checkAuthMethod).toBeCalledWith({
140
- apiKey: 'test-api-key',
141
- betterAuthAuthorized: false,
142
- clerkAuth: {},
143
- nextAuthAuthorized: true,
144
- });
145
- });
146
-
147
99
  it('should return InternalServerError error when throw a unknown error', async () => {
148
100
  const mockParams = Promise.resolve({ provider: 'test-provider' });
149
101
  vi.mocked(getXorPayload).mockImplementationOnce(() => {
@@ -9,10 +9,6 @@ import { initModelRuntimeFromDB } from '@/server/modules/ModelRuntime';
9
9
 
10
10
  import { GET } from './route';
11
11
 
12
- vi.mock('@clerk/nextjs/server', () => ({
13
- getAuth: vi.fn(),
14
- }));
15
-
16
12
  vi.mock('@/app/(backend)/middleware/auth/utils', () => ({
17
13
  checkAuthMethod: vi.fn(),
18
14
  }));
@@ -21,6 +17,14 @@ vi.mock('@lobechat/utils/server', () => ({
21
17
  getXorPayload: vi.fn(),
22
18
  }));
23
19
 
20
+ vi.mock('@/envs/auth', async (importOriginal) => {
21
+ const actual = await importOriginal<typeof import('@/envs/auth')>();
22
+ return {
23
+ ...actual,
24
+ enableBetterAuth: false,
25
+ };
26
+ });
27
+
24
28
  vi.mock('@/server/modules/ModelRuntime', () => ({
25
29
  initModelRuntimeFromDB: vi.fn(),
26
30
  }));
@@ -68,7 +68,8 @@ const BtnListLoading = memo(() => {
68
68
  * ref: https://authjs.dev/guides/pages/signin
69
69
  */
70
70
  export default memo(() => {
71
- const { t } = useTranslation('clerk');
71
+ const { t } = useTranslation('auth');
72
+ const { t: tCommon } = useTranslation('common');
72
73
  const router = useRouter();
73
74
  const [loadingProvider, setLoadingProvider] = useState<string | null>(null);
74
75
 
@@ -100,9 +101,9 @@ export default memo(() => {
100
101
  };
101
102
 
102
103
  const footerBtns = [
103
- { href: DOCUMENTS_REFER_URL, id: 0, label: t('footerPageLink__help') },
104
- { href: PRIVACY_URL, id: 1, label: t('footerPageLink__privacy') },
105
- { href: TERMS_URL, id: 2, label: t('footerPageLink__terms') },
104
+ { href: DOCUMENTS_REFER_URL, id: 0, label: tCommon('document') },
105
+ { href: PRIVACY_URL, id: 1, label: t('footer.privacy') },
106
+ { href: TERMS_URL, id: 2, label: t('footer.terms') },
106
107
  ];
107
108
 
108
109
  return (
@@ -116,10 +117,10 @@ export default memo(() => {
116
117
  <div>
117
118
  <LobeHub size={48} />
118
119
  </div>
119
- {t('signIn.start.title', { applicationName: BRANDING_NAME })}
120
+ {t('signin.title')}
120
121
  </Text>
121
122
  <Text as={'p'} className={styles.description}>
122
- {t('signIn.start.subtitle')}
123
+ {t('signin.subtitle', { appName: BRANDING_NAME })}
123
124
  </Text>
124
125
  </div>
125
126
  {/* Content */}
@@ -1,6 +1,4 @@
1
- import { SignUp } from '@clerk/nextjs';
2
-
3
- import { enableBetterAuth, enableClerk } from '@/envs/auth';
1
+ import { enableBetterAuth } from '@/envs/auth';
4
2
  import { notFound } from '@/libs/next/navigation';
5
3
  import { metadataModule } from '@/server/metadata';
6
4
  import { translation } from '@/server/translation';
@@ -12,15 +10,6 @@ import BetterAuthSignUpForm from './BetterAuthSignUpForm';
12
10
  export const generateMetadata = async (props: DynamicLayoutProps) => {
13
11
  const locale = await RouteVariants.getLocale(props);
14
12
 
15
- if (enableClerk) {
16
- const { t } = await translation('clerk', locale);
17
- return metadataModule.generate({
18
- description: t('signUp.start.subtitle'),
19
- title: t('signUp.start.title'),
20
- url: '/signup',
21
- });
22
- }
23
-
24
13
  if (enableBetterAuth) {
25
14
  const { t } = await translation('auth', locale);
26
15
  return metadataModule.generate({
@@ -37,10 +26,6 @@ export const generateMetadata = async (props: DynamicLayoutProps) => {
37
26
  };
38
27
 
39
28
  const Page = () => {
40
- if (enableClerk) {
41
- return <SignUp path="/signup" />;
42
- }
43
-
44
29
  if (enableBetterAuth) {
45
30
  return <BetterAuthSignUpForm />;
46
31
  }
@@ -42,7 +42,7 @@ const AgentList = memo<{ onMoreClick?: () => void }>(({ onMoreClick }) => {
42
42
 
43
43
  return (
44
44
  <>
45
- <InboxItem />
45
+ <InboxItem style={{ minHeight: 36 }} />
46
46
  {showPinned && <SessionList dataSource={pinnedList!} />}
47
47
  {showCustom && <Group dataSource={customList!} />}
48
48
  {showDefault && (
@@ -4,10 +4,10 @@ import { getKlavisServerByServerIdentifier, getLobehubSkillProviderById } from '
4
4
  import { Avatar, Flexbox, Icon } from '@lobehub/ui';
5
5
  import { createStaticStyles } from 'antd-style';
6
6
  import { Blocks } from 'lucide-react';
7
- import { type ReactNode, createElement, memo, useMemo, useState } from 'react';
7
+ import { type ReactNode, createElement, memo, useCallback, useMemo } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
 
10
- import SkillStore from '@/features/SkillStore';
10
+ import { createSkillStoreModal } from '@/features/SkillStore';
11
11
  import { serverConfigSelectors, useServerConfigStore } from '@/store/serverConfig';
12
12
  import { useToolStore } from '@/store/tool';
13
13
 
@@ -61,7 +61,6 @@ const BANNER_SKILL_IDS = [
61
61
 
62
62
  const SkillInstallBanner = memo(() => {
63
63
  const { t } = useTranslation('plugin');
64
- const [open, setOpen] = useState(false);
65
64
 
66
65
  const isLobehubSkillEnabled = useServerConfigStore(serverConfigSelectors.enableLobehubSkill);
67
66
  const isKlavisEnabled = useServerConfigStore(serverConfigSelectors.enableKlavis);
@@ -108,20 +107,21 @@ const SkillInstallBanner = memo(() => {
108
107
  return items;
109
108
  }, []);
110
109
 
110
+ const handleOpenStore = useCallback(() => {
111
+ createSkillStoreModal();
112
+ }, []);
113
+
111
114
  // Don't show banner if no skills are enabled
112
115
  if (!isLobehubSkillEnabled && !isKlavisEnabled) return null;
113
116
 
114
117
  return (
115
- <>
116
- <div className={styles.banner} onClick={() => setOpen(true)}>
117
- <Flexbox align="center" gap={8} horizontal>
118
- <Icon className={styles.icon} icon={Blocks} size={18} />
119
- <span className={styles.text}>{t('skillInstallBanner.title')}</span>
120
- </Flexbox>
121
- {avatarItems.length > 0 && <Avatar.Group items={avatarItems} shape="circle" size={24} />}
122
- </div>
123
- <SkillStore open={open} setOpen={setOpen} />
124
- </>
118
+ <div className={styles.banner} onClick={handleOpenStore}>
119
+ <Flexbox align="center" gap={8} horizontal>
120
+ <Icon className={styles.icon} icon={Blocks} size={18} />
121
+ <span className={styles.text}>{t('skillInstallBanner.title')}</span>
122
+ </Flexbox>
123
+ {avatarItems.length > 0 && <Avatar.Group items={avatarItems} shape="circle" size={24} />}
124
+ </div>
125
125
  );
126
126
  });
127
127
 
@@ -3,12 +3,12 @@
3
3
  import { Avatar, Block, Center, Flexbox, Icon, Text } from '@lobehub/ui';
4
4
  import { cssVar } from 'antd-style';
5
5
  import { FileTextIcon } from 'lucide-react';
6
- import markdownToTxt from 'markdown-to-txt';
7
6
  import { memo } from 'react';
8
7
 
9
8
  import Time from '@/app/[variants]/(main)/home/features/components/Time';
10
9
  import { RECENT_BLOCK_SIZE } from '@/app/[variants]/(main)/home/features/const';
11
10
  import { type FileListItem } from '@/types/files';
11
+ import markdownToTxt from '@/utils/markdownToTxt';
12
12
 
13
13
  // Helper to extract title from markdown content
14
14
  const extractTitle = (content: string): string | null => {
@@ -24,7 +24,7 @@ const getPreviewText = (item: FileListItem): string => {
24
24
  if (!item.content) return '';
25
25
 
26
26
  // Convert markdown to plain text
27
- let plainText = markdownToTxt(item.content);
27
+ let plainText = markdownToTxt(item.content.slice(0, 120));
28
28
 
29
29
  // Remove the title line if it exists
30
30
  const title = extractTitle(item.content);
@@ -20,7 +20,6 @@ import {
20
20
  Mic2,
21
21
  PaletteIcon,
22
22
  PieChart,
23
- ShieldCheck,
24
23
  Sparkles,
25
24
  UserCircle,
26
25
  } from 'lucide-react';
@@ -32,7 +31,7 @@ import { electronSyncSelectors } from '@/store/electron/selectors';
32
31
  import { SettingsTabs } from '@/store/global/initialState';
33
32
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
34
33
  import { useUserStore } from '@/store/user';
35
- import { authSelectors, userProfileSelectors } from '@/store/user/slices/auth/selectors';
34
+ import { userProfileSelectors } from '@/store/user/slices/auth/selectors';
36
35
 
37
36
  export enum SettingsGroupKey {
38
37
  AIConfig = 'ai-config',
@@ -61,8 +60,7 @@ export const useCategory = () => {
61
60
  const mobile = useServerConfigStore((s) => s.isMobile);
62
61
  const { enableSTT, hideDocs, showAiImage, showApiKeyManage } =
63
62
  useServerConfigStore(featureFlagsSelectors);
64
- const [isLoginWithClerk, avatar, username] = useUserStore((s) => [
65
- authSelectors.isLoginWithClerk(s),
63
+ const [avatar, username] = useUserStore((s) => [
66
64
  userProfileSelectors.userAvatar(s),
67
65
  userProfileSelectors.nickName(s),
68
66
  ]);
@@ -87,11 +85,6 @@ export const useCategory = () => {
87
85
  key: SettingsTabs.Profile,
88
86
  label: username ? username : tAuth('tab.profile'),
89
87
  },
90
- isLoginWithClerk && {
91
- icon: ShieldCheck,
92
- key: SettingsTabs.Security,
93
- label: tAuth('tab.security'),
94
- },
95
88
  {
96
89
  icon: ChartColumnBigIcon,
97
90
  key: SettingsTabs.Stats,
@@ -237,18 +230,7 @@ export const useCategory = () => {
237
230
  });
238
231
 
239
232
  return groups;
240
- }, [
241
- t,
242
- tAuth,
243
- enableSTT,
244
- hideDocs,
245
- mobile,
246
- showAiImage,
247
- showApiKeyManage,
248
- isLoginWithClerk,
249
- avatarUrl,
250
- username,
251
- ]);
233
+ }, [t, tAuth, enableSTT, hideDocs, mobile, showAiImage, showApiKeyManage, avatarUrl, username]);
252
234
 
253
235
  return categoryGroups;
254
236
  };
@@ -7,7 +7,6 @@ import { useCallback, useState } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
8
8
 
9
9
  import { fetchErrorNotification } from '@/components/Error/fetchErrorNotification';
10
- import { enableAuth } from '@/envs/auth';
11
10
  import UserAvatar from '@/features/User/UserAvatar';
12
11
  import { useUserStore } from '@/store/user';
13
12
  import { authSelectors } from '@/store/user/selectors';
@@ -54,7 +53,7 @@ const AvatarRow = ({ mobile }: AvatarRowProps) => {
54
53
  [updateAvatar],
55
54
  );
56
55
 
57
- const canUpload = !enableAuth || isLogin;
56
+ const canUpload = isLogin;
58
57
 
59
58
  const avatarContent = canUpload ? (
60
59
  <Spin indicator={<LoadingOutlined spin />} spinning={uploading}>