@lobehub/lobehub 2.0.0-next.221 → 2.0.0-next.223
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/claude-auto-testing.yml +6 -3
- package/.github/workflows/claude-dedupe-issues.yml +8 -1
- package/.github/workflows/claude-issue-triage.yml +8 -14
- package/.github/workflows/claude-translate-comments.yml +6 -3
- package/.github/workflows/claude-translator.yml +12 -14
- package/.github/workflows/claude.yml +10 -20
- package/.github/workflows/test.yml +26 -0
- package/CHANGELOG.md +58 -0
- package/changelog/v1.json +18 -0
- package/e2e/package.json +1 -1
- package/e2e/src/mocks/index.ts +2 -2
- package/e2e/src/steps/{discover → community}/detail-pages.steps.ts +8 -8
- package/e2e/src/steps/{discover → community}/interactions.steps.ts +4 -4
- package/locales/zh-CN/components.json +1 -0
- package/package.json +3 -3
- package/packages/const/src/index.ts +0 -1
- package/packages/memory-user-memory/package.json +1 -0
- package/packages/memory-user-memory/src/extractors/context.test.ts +3 -2
- package/packages/memory-user-memory/src/extractors/experience.test.ts +3 -2
- package/packages/memory-user-memory/src/extractors/identity.test.ts +23 -6
- package/packages/memory-user-memory/src/extractors/preference.test.ts +3 -2
- package/packages/memory-user-memory/vitest.config.ts +4 -0
- package/packages/model-runtime/src/providers/replicate/index.ts +1 -1
- package/packages/ssrf-safe-fetch/index.test.ts +2 -2
- package/packages/ssrf-safe-fetch/package.json +3 -2
- package/packages/types/src/serverConfig.ts +2 -0
- package/packages/utils/package.json +1 -1
- package/packages/utils/src/client/xor-obfuscation.test.ts +32 -32
- package/packages/utils/src/client/xor-obfuscation.ts +3 -4
- package/packages/utils/src/imageToBase64.ts +1 -1
- package/packages/utils/src/server/__tests__/auth.test.ts +1 -1
- package/packages/utils/src/server/auth.ts +1 -1
- package/packages/utils/src/server/correctOIDCUrl.test.ts +80 -19
- package/packages/utils/src/server/correctOIDCUrl.ts +89 -24
- package/packages/utils/src/server/index.ts +1 -0
- package/packages/utils/src/server/xor.test.ts +9 -7
- package/packages/utils/src/server/xor.ts +1 -1
- package/packages/web-crawler/package.json +1 -1
- package/packages/web-crawler/src/crawImpl/__tests__/naive.test.ts +1 -1
- package/packages/web-crawler/src/crawImpl/naive.ts +1 -1
- package/scripts/prebuild.mts +58 -1
- package/src/app/(backend)/api/auth/[...all]/route.ts +2 -1
- package/src/app/(backend)/middleware/auth/index.ts +3 -3
- package/src/app/(backend)/middleware/auth/utils.test.ts +1 -1
- package/src/app/(backend)/middleware/auth/utils.ts +1 -1
- package/src/app/(backend)/oidc/callback/desktop/route.ts +7 -36
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +2 -2
- package/src/app/(backend)/webapi/models/[provider]/route.test.ts +1 -1
- package/src/app/(backend)/webapi/plugin/gateway/route.ts +1 -1
- package/src/app/(backend)/webapi/proxy/route.ts +1 -1
- package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +1 -1
- package/src/app/[variants]/(auth)/reset-password/layout.tsx +1 -1
- package/src/app/[variants]/(auth)/signin/layout.tsx +1 -1
- package/src/app/[variants]/(auth)/signin/useSignIn.ts +2 -2
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -1
- package/src/app/[variants]/(auth)/signup/[[...signup]]/useSignUp.tsx +12 -6
- package/src/app/[variants]/(auth)/verify-email/layout.tsx +1 -1
- package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -1
- package/src/app/[variants]/(main)/settings/security/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +1 -1
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +1 -1
- package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -1
- package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +1 -1
- package/src/components/ModelSelect/index.tsx +103 -72
- package/src/envs/auth.ts +30 -9
- package/src/features/Conversation/Messages/AssistantGroup/components/EditState.tsx +15 -32
- package/src/features/Conversation/Messages/AssistantGroup/index.tsx +9 -7
- package/src/features/EditorModal/EditorCanvas.tsx +31 -50
- package/src/features/EditorModal/TextareCanvas.tsx +3 -1
- package/src/features/EditorModal/index.tsx +14 -4
- package/src/features/ModelSwitchPanel/components/Footer.tsx +42 -0
- package/src/features/ModelSwitchPanel/components/List/MultipleProvidersModelItem.tsx +103 -0
- package/src/features/ModelSwitchPanel/components/List/SingleProviderModelItem.tsx +24 -0
- package/src/features/ModelSwitchPanel/components/List/VirtualItemRenderer.tsx +180 -0
- package/src/features/ModelSwitchPanel/components/List/index.tsx +99 -0
- package/src/features/ModelSwitchPanel/components/PanelContent.tsx +77 -0
- package/src/features/ModelSwitchPanel/components/Toolbar.tsx +54 -0
- package/src/features/ModelSwitchPanel/const.ts +29 -0
- package/src/features/ModelSwitchPanel/hooks/useBuildVirtualItems.ts +122 -0
- package/src/features/ModelSwitchPanel/hooks/useCurrentModelName.ts +18 -0
- package/src/features/ModelSwitchPanel/hooks/useDelayedRender.ts +18 -0
- package/src/features/ModelSwitchPanel/hooks/useModelAndProvider.ts +14 -0
- package/src/features/ModelSwitchPanel/hooks/usePanelHandlers.ts +33 -0
- package/src/features/ModelSwitchPanel/hooks/usePanelSize.ts +33 -0
- package/src/features/ModelSwitchPanel/hooks/usePanelState.ts +20 -0
- package/src/features/ModelSwitchPanel/index.tsx +25 -706
- package/src/features/ModelSwitchPanel/styles.ts +58 -0
- package/src/features/ModelSwitchPanel/types.ts +73 -0
- package/src/features/ModelSwitchPanel/utils.ts +24 -0
- package/src/features/User/UserPanel/PanelContent.tsx +1 -1
- package/src/features/User/__tests__/PanelContent.test.tsx +1 -1
- package/src/features/User/__tests__/UserAvatar.test.tsx +1 -1
- package/src/features/User/__tests__/useMenu.test.tsx +1 -1
- package/src/layout/GlobalProvider/StoreInitialization.tsx +2 -1
- package/src/libs/better-auth/auth-client.ts +7 -3
- package/src/libs/better-auth/define-config.ts +2 -2
- package/src/libs/next/proxy/define-config.ts +9 -6
- package/src/libs/oidc-provider/provider.test.ts +1 -1
- package/src/libs/trpc/async/context.ts +1 -1
- package/src/libs/trpc/lambda/context.ts +7 -8
- package/src/libs/trpc/middleware/userAuth.ts +1 -1
- package/src/libs/trusted-client/getSessionUser.ts +1 -1
- package/src/locales/default/components.ts +1 -0
- package/src/server/globalConfig/index.ts +2 -0
- package/src/server/routers/async/caller.ts +1 -1
- package/src/server/routers/lambda/__tests__/user.test.ts +2 -2
- package/src/server/routers/lambda/user.ts +2 -1
- package/src/services/_auth.ts +3 -3
- package/src/services/chat/index.ts +1 -1
- package/src/services/chat/mecha/contextEngineering.ts +1 -1
- package/src/store/global/initialState.ts +10 -0
- package/src/store/global/selectors/systemStatus.ts +5 -0
- package/src/store/serverConfig/selectors.ts +5 -1
- package/src/store/tool/slices/mcpStore/action.ts +74 -75
- package/src/store/user/slices/auth/action.test.ts +1 -1
- package/src/store/user/slices/auth/action.ts +1 -1
- package/src/store/user/slices/auth/initialState.ts +1 -1
- package/src/store/user/slices/auth/selectors.test.ts +1 -1
- package/src/store/user/slices/auth/selectors.ts +1 -1
- package/src/store/user/slices/common/action.ts +1 -1
- package/src/store/userMemory/slices/context/action.ts +6 -6
- package/packages/const/src/auth.ts +0 -14
- /package/e2e/src/features/{discover → community}/detail-pages.feature +0 -0
- /package/e2e/src/features/{discover → community}/interactions.feature +0 -0
- /package/e2e/src/features/{discover → community}/smoke.feature +0 -0
- /package/e2e/src/mocks/{discover → community}/data.ts +0 -0
- /package/e2e/src/mocks/{discover → community}/handlers.ts +0 -0
- /package/e2e/src/mocks/{discover → community}/index.ts +0 -0
- /package/e2e/src/mocks/{discover → community}/types.ts +0 -0
- /package/e2e/src/steps/{discover → community}/smoke.steps.ts +0 -0
|
@@ -7,7 +7,7 @@ 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 '@/
|
|
10
|
+
import { enableAuth } from '@/envs/auth';
|
|
11
11
|
import UserAvatar from '@/features/User/UserAvatar';
|
|
12
12
|
import { useUserStore } from '@/store/user';
|
|
13
13
|
import { authSelectors } from '@/store/user/selectors';
|
|
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Navigate } from 'react-router-dom';
|
|
7
7
|
|
|
8
8
|
import SettingHeader from '@/app/[variants]/(main)/settings/features/SettingHeader';
|
|
9
|
-
import { enableClerk } from '@/
|
|
9
|
+
import { enableClerk } from '@/envs/auth';
|
|
10
10
|
|
|
11
11
|
const ClerkProfile = dynamic(() => import('./features/ClerkProfile'), {
|
|
12
12
|
loading: () => (
|
|
@@ -4,7 +4,7 @@ import { Flexbox } from '@lobehub/ui';
|
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { Link } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
-
import { enableAuth } from '@/
|
|
7
|
+
import { enableAuth } from '@/envs/auth';
|
|
8
8
|
import DataStatistics from '@/features/User/DataStatistics';
|
|
9
9
|
import UserInfo from '@/features/User/UserInfo';
|
|
10
10
|
import UserLoginOrSignup from '@/features/User/UserLoginOrSignup/Community';
|
|
@@ -6,7 +6,7 @@ import { memo } from 'react';
|
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { useNavigate } from 'react-router-dom';
|
|
8
8
|
|
|
9
|
-
import { enableAuth } from '@/
|
|
9
|
+
import { enableAuth } from '@/envs/auth';
|
|
10
10
|
import { useQueryState } from '@/hooks/useQueryParam';
|
|
11
11
|
import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
|
|
12
12
|
import { type SettingsTabs } from '@/store/global/initialState';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ChatModelCard } from '@lobechat/types';
|
|
2
|
-
import { type IconAvatarProps, ModelIcon, ProviderIcon } from '@lobehub/icons';
|
|
3
|
-
import { Avatar, Flexbox, Icon, Tag, Text, Tooltip } from '@lobehub/ui';
|
|
2
|
+
import { type IconAvatarProps, LobeHub, ModelIcon, ProviderIcon } from '@lobehub/icons';
|
|
3
|
+
import { Avatar, Flexbox, FlexboxProps, Icon, Tag, Text, Tooltip } from '@lobehub/ui';
|
|
4
4
|
import { createStaticStyles, useResponsive } from 'antd-style';
|
|
5
5
|
import {
|
|
6
6
|
Infinity,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from 'lucide-react';
|
|
15
15
|
import { type ModelAbilities } from 'model-bank';
|
|
16
16
|
import numeral from 'numeral';
|
|
17
|
-
import { type ComponentProps, type FC, memo, useState } from 'react';
|
|
17
|
+
import { CSSProperties, type ComponentProps, type FC, memo, useState } from 'react';
|
|
18
18
|
import { useTranslation } from 'react-i18next';
|
|
19
19
|
|
|
20
20
|
import { type AiProviderSourceType } from '@/types/aiProvider';
|
|
@@ -64,6 +64,7 @@ interface ModelInfoTagsProps extends ModelAbilities {
|
|
|
64
64
|
directionReverse?: boolean;
|
|
65
65
|
isCustom?: boolean;
|
|
66
66
|
placement?: 'top' | 'right';
|
|
67
|
+
style?: CSSProperties;
|
|
67
68
|
/**
|
|
68
69
|
* Whether to render tooltip overlays for each tag.
|
|
69
70
|
* Disable this when rendering a large list (e.g. dropdown menus) to avoid mounting hundreds of Tooltip instances.
|
|
@@ -237,13 +238,13 @@ const Context = memo(
|
|
|
237
238
|
);
|
|
238
239
|
|
|
239
240
|
export const ModelInfoTags = memo<ModelInfoTagsProps>(
|
|
240
|
-
({ directionReverse, placement = 'top', withTooltip = true, ...model }) => {
|
|
241
|
+
({ directionReverse, placement = 'top', withTooltip = true, style, ...model }) => {
|
|
241
242
|
return (
|
|
242
243
|
<Flexbox
|
|
243
244
|
className={TAG_CLASSNAME}
|
|
244
245
|
direction={directionReverse ? 'horizontal-reverse' : 'horizontal'}
|
|
245
|
-
gap={
|
|
246
|
-
style={{ marginLeft: 'auto' }}
|
|
246
|
+
gap={2}
|
|
247
|
+
style={{ marginLeft: 'auto', ...style }}
|
|
247
248
|
width={'fit-content'}
|
|
248
249
|
>
|
|
249
250
|
<FeatureTags
|
|
@@ -271,7 +272,7 @@ export const ModelInfoTags = memo<ModelInfoTagsProps>(
|
|
|
271
272
|
},
|
|
272
273
|
);
|
|
273
274
|
|
|
274
|
-
interface ModelItemRenderProps extends ChatModelCard {
|
|
275
|
+
interface ModelItemRenderProps extends ChatModelCard, Partial<Omit<FlexboxProps, 'id' | 'title'>> {
|
|
275
276
|
abilities?: ModelAbilities;
|
|
276
277
|
infoTagTooltip?: boolean;
|
|
277
278
|
/**
|
|
@@ -286,10 +287,9 @@ interface ModelItemRenderProps extends ChatModelCard {
|
|
|
286
287
|
showInfoTag?: boolean;
|
|
287
288
|
}
|
|
288
289
|
|
|
289
|
-
export const ModelItemRender = memo<ModelItemRenderProps>(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const {
|
|
290
|
+
export const ModelItemRender = memo<ModelItemRenderProps>(
|
|
291
|
+
({
|
|
292
|
+
showInfoTag = true,
|
|
293
293
|
abilities,
|
|
294
294
|
infoTagTooltip = true,
|
|
295
295
|
infoTagTooltipOnHover = false,
|
|
@@ -302,88 +302,119 @@ export const ModelItemRender = memo<ModelItemRenderProps>(({ showInfoTag = true,
|
|
|
302
302
|
search,
|
|
303
303
|
video,
|
|
304
304
|
vision,
|
|
305
|
-
|
|
305
|
+
id,
|
|
306
|
+
displayName,
|
|
307
|
+
releasedAt,
|
|
308
|
+
...rest
|
|
309
|
+
}) => {
|
|
310
|
+
const { mobile } = useResponsive();
|
|
311
|
+
const [hovered, setHovered] = useState(false);
|
|
306
312
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
<Flexbox
|
|
317
|
-
align={'center'}
|
|
318
|
-
gap={32}
|
|
319
|
-
horizontal
|
|
320
|
-
justify={'space-between'}
|
|
321
|
-
onMouseEnter={shouldLazyMountTooltip && !hovered ? () => setHovered(true) : undefined}
|
|
322
|
-
style={{
|
|
323
|
-
overflow: 'hidden',
|
|
324
|
-
position: 'relative',
|
|
325
|
-
width: '100%',
|
|
326
|
-
}}
|
|
327
|
-
>
|
|
313
|
+
const shouldLazyMountTooltip = infoTagTooltipOnHover && !mobile;
|
|
314
|
+
/**
|
|
315
|
+
* When `infoTagTooltipOnHover` is enabled, we don't mount Tooltip components until the row is hovered.
|
|
316
|
+
* This avoids creating many overlays on dropdown open, while keeping the tooltip UX on demand.
|
|
317
|
+
*/
|
|
318
|
+
const withTooltip = infoTagTooltip && (!shouldLazyMountTooltip || hovered);
|
|
319
|
+
const displayNameOrId = displayName || id;
|
|
320
|
+
|
|
321
|
+
return (
|
|
328
322
|
<Flexbox
|
|
329
323
|
align={'center'}
|
|
330
|
-
gap={
|
|
324
|
+
gap={32}
|
|
331
325
|
horizontal
|
|
332
|
-
|
|
326
|
+
justify={'space-between'}
|
|
327
|
+
onMouseEnter={shouldLazyMountTooltip && !hovered ? () => setHovered(true) : undefined}
|
|
328
|
+
{...rest}
|
|
329
|
+
style={{
|
|
330
|
+
overflow: 'hidden',
|
|
331
|
+
position: 'relative',
|
|
332
|
+
width: '100%',
|
|
333
|
+
...rest.style,
|
|
334
|
+
}}
|
|
333
335
|
>
|
|
334
|
-
<
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
tooltip: displayName,
|
|
340
|
-
}
|
|
341
|
-
: true
|
|
342
|
-
}
|
|
343
|
-
style={mobile ? { maxWidth: '60vw' } : { minWidth: 0, overflow: 'hidden' }}
|
|
336
|
+
<Flexbox
|
|
337
|
+
align={'center'}
|
|
338
|
+
gap={8}
|
|
339
|
+
horizontal
|
|
340
|
+
style={{ flexShrink: 1, minWidth: 0, overflow: 'hidden' }}
|
|
344
341
|
>
|
|
345
|
-
{
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
342
|
+
<ModelIcon model={id} size={20} />
|
|
343
|
+
<Text
|
|
344
|
+
ellipsis={
|
|
345
|
+
withTooltip
|
|
346
|
+
? {
|
|
347
|
+
tooltip: displayNameOrId,
|
|
348
|
+
}
|
|
349
|
+
: true
|
|
350
|
+
}
|
|
351
|
+
style={mobile ? { maxWidth: '60vw' } : { minWidth: 0, overflow: 'hidden' }}
|
|
352
|
+
>
|
|
353
|
+
{displayNameOrId}
|
|
354
|
+
</Text>
|
|
355
|
+
{newBadgeLabel ? (
|
|
356
|
+
<NewModelBadgeCore label={newBadgeLabel} releasedAt={releasedAt} />
|
|
357
|
+
) : (
|
|
358
|
+
<NewModelBadgeI18n releasedAt={releasedAt} />
|
|
359
|
+
)}
|
|
360
|
+
</Flexbox>
|
|
361
|
+
{showInfoTag && (
|
|
362
|
+
<ModelInfoTags
|
|
363
|
+
contextWindowTokens={contextWindowTokens}
|
|
364
|
+
files={files ?? abilities?.files}
|
|
365
|
+
functionCall={functionCall ?? abilities?.functionCall}
|
|
366
|
+
imageOutput={imageOutput ?? abilities?.imageOutput}
|
|
367
|
+
reasoning={reasoning ?? abilities?.reasoning}
|
|
368
|
+
search={search ?? abilities?.search}
|
|
369
|
+
style={{ zoom: 0.9 }}
|
|
370
|
+
video={video ?? abilities?.video}
|
|
371
|
+
vision={vision ?? abilities?.vision}
|
|
372
|
+
withTooltip={withTooltip}
|
|
373
|
+
/>
|
|
351
374
|
)}
|
|
352
375
|
</Flexbox>
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
files={files ?? abilities?.files}
|
|
357
|
-
functionCall={functionCall ?? abilities?.functionCall}
|
|
358
|
-
imageOutput={imageOutput ?? abilities?.imageOutput}
|
|
359
|
-
reasoning={reasoning ?? abilities?.reasoning}
|
|
360
|
-
search={search ?? abilities?.search}
|
|
361
|
-
video={video ?? abilities?.video}
|
|
362
|
-
vision={vision ?? abilities?.vision}
|
|
363
|
-
withTooltip={withTooltip}
|
|
364
|
-
/>
|
|
365
|
-
)}
|
|
366
|
-
</Flexbox>
|
|
367
|
-
);
|
|
368
|
-
});
|
|
376
|
+
);
|
|
377
|
+
},
|
|
378
|
+
);
|
|
369
379
|
|
|
370
380
|
interface ProviderItemRenderProps {
|
|
371
381
|
logo?: string;
|
|
372
382
|
name: string;
|
|
373
383
|
provider: string;
|
|
384
|
+
size?: number;
|
|
374
385
|
source?: AiProviderSourceType;
|
|
386
|
+
type?: 'mono' | 'color' | 'avatar';
|
|
375
387
|
}
|
|
376
388
|
|
|
377
389
|
export const ProviderItemRender = memo<ProviderItemRenderProps>(
|
|
378
|
-
({ provider, name, source, logo }) => {
|
|
390
|
+
({ provider, name, source, logo, type = 'mono', size = 16 }) => {
|
|
391
|
+
const isMono = type === 'mono';
|
|
379
392
|
return (
|
|
380
|
-
<Flexbox
|
|
393
|
+
<Flexbox
|
|
394
|
+
align={'center'}
|
|
395
|
+
gap={6}
|
|
396
|
+
horizontal
|
|
397
|
+
style={{
|
|
398
|
+
overflow: 'hidden',
|
|
399
|
+
}}
|
|
400
|
+
width={'100%'}
|
|
401
|
+
>
|
|
381
402
|
{source === 'custom' && !!logo ? (
|
|
382
|
-
<Avatar
|
|
403
|
+
<Avatar
|
|
404
|
+
avatar={logo}
|
|
405
|
+
shape={'circle'}
|
|
406
|
+
size={size}
|
|
407
|
+
style={isMono ? { filter: 'grayscale(1)' } : {}}
|
|
408
|
+
title={name}
|
|
409
|
+
/>
|
|
410
|
+
) : provider === 'lobehub' ? (
|
|
411
|
+
<LobeHub.Morden size={size} />
|
|
383
412
|
) : (
|
|
384
|
-
<ProviderIcon provider={provider} size={
|
|
413
|
+
<ProviderIcon provider={provider} size={size} type={type} />
|
|
385
414
|
)}
|
|
386
|
-
{
|
|
415
|
+
<Text color={'inherit'} ellipsis>
|
|
416
|
+
{name}
|
|
417
|
+
</Text>
|
|
387
418
|
</Flexbox>
|
|
388
419
|
);
|
|
389
420
|
},
|
package/src/envs/auth.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
|
|
2
|
-
import { enableBetterAuth, enableClerk, enableNextAuth } from '@lobechat/const';
|
|
3
2
|
import { createEnv } from '@t3-oss/env-nextjs';
|
|
4
3
|
import { z } from 'zod';
|
|
5
4
|
|
|
@@ -52,7 +51,8 @@ declare global {
|
|
|
52
51
|
// ===== Auth (shared by Better Auth / Next Auth) ===== //
|
|
53
52
|
AUTH_SECRET?: string;
|
|
54
53
|
NEXT_PUBLIC_AUTH_URL?: string;
|
|
55
|
-
|
|
54
|
+
AUTH_EMAIL_VERIFICATION?: string;
|
|
55
|
+
ENABLE_MAGIC_LINK?: string;
|
|
56
56
|
AUTH_SSO_PROVIDERS?: string;
|
|
57
57
|
AUTH_TRUSTED_ORIGINS?: string;
|
|
58
58
|
|
|
@@ -172,8 +172,6 @@ export const getAuthConfig = () => {
|
|
|
172
172
|
// ---------------------------------- better auth ----------------------------------
|
|
173
173
|
NEXT_PUBLIC_ENABLE_BETTER_AUTH: z.boolean().optional(),
|
|
174
174
|
NEXT_PUBLIC_AUTH_URL: z.string().optional(),
|
|
175
|
-
NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION: z.boolean().optional().default(false),
|
|
176
|
-
NEXT_PUBLIC_ENABLE_MAGIC_LINK: z.boolean().optional().default(false),
|
|
177
175
|
|
|
178
176
|
// ---------------------------------- next auth ----------------------------------
|
|
179
177
|
NEXT_PUBLIC_ENABLE_NEXT_AUTH: z.boolean().optional(),
|
|
@@ -187,6 +185,8 @@ export const getAuthConfig = () => {
|
|
|
187
185
|
AUTH_SECRET: z.string().optional(),
|
|
188
186
|
AUTH_SSO_PROVIDERS: z.string().optional().default(''),
|
|
189
187
|
AUTH_TRUSTED_ORIGINS: z.string().optional(),
|
|
188
|
+
AUTH_EMAIL_VERIFICATION: z.boolean().optional().default(false),
|
|
189
|
+
ENABLE_MAGIC_LINK: z.boolean().optional().default(false),
|
|
190
190
|
|
|
191
191
|
// ---------------------------------- next auth ----------------------------------
|
|
192
192
|
NEXT_AUTH_SECRET: z.string().optional(),
|
|
@@ -289,17 +289,23 @@ export const getAuthConfig = () => {
|
|
|
289
289
|
|
|
290
290
|
runtimeEnv: {
|
|
291
291
|
// Clerk
|
|
292
|
-
NEXT_PUBLIC_ENABLE_CLERK_AUTH:
|
|
292
|
+
NEXT_PUBLIC_ENABLE_CLERK_AUTH:
|
|
293
|
+
process.env.NEXT_PUBLIC_ENABLE_CLERK_AUTH === '1' ||
|
|
294
|
+
!!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
|
|
293
295
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
|
|
294
296
|
CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
|
|
295
297
|
CLERK_WEBHOOK_SECRET: process.env.CLERK_WEBHOOK_SECRET,
|
|
296
298
|
|
|
297
299
|
// ---------------------------------- better auth ----------------------------------
|
|
298
|
-
NEXT_PUBLIC_ENABLE_BETTER_AUTH:
|
|
300
|
+
NEXT_PUBLIC_ENABLE_BETTER_AUTH: process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1',
|
|
299
301
|
// Fallback to NEXTAUTH_URL origin or Vercel deployment domain for seamless migration from next-auth
|
|
300
302
|
NEXT_PUBLIC_AUTH_URL: resolvePublicAuthUrl(),
|
|
301
|
-
|
|
302
|
-
|
|
303
|
+
// Fallback to NEXT_PUBLIC_* for seamless migration
|
|
304
|
+
AUTH_EMAIL_VERIFICATION:
|
|
305
|
+
process.env.AUTH_EMAIL_VERIFICATION === '1' ||
|
|
306
|
+
process.env.NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION === '1',
|
|
307
|
+
ENABLE_MAGIC_LINK:
|
|
308
|
+
process.env.ENABLE_MAGIC_LINK === '1' || process.env.NEXT_PUBLIC_ENABLE_MAGIC_LINK === '1',
|
|
303
309
|
// Fallback to NEXT_AUTH_SECRET for seamless migration from next-auth
|
|
304
310
|
AUTH_SECRET: process.env.AUTH_SECRET || process.env.NEXT_AUTH_SECRET,
|
|
305
311
|
// Fallback to NEXT_AUTH_SSO_PROVIDERS for seamless migration from next-auth
|
|
@@ -312,7 +318,7 @@ export const getAuthConfig = () => {
|
|
|
312
318
|
AUTH_COGNITO_USERPOOL_ID: process.env.AUTH_COGNITO_USERPOOL_ID,
|
|
313
319
|
|
|
314
320
|
// ---------------------------------- next auth ----------------------------------
|
|
315
|
-
NEXT_PUBLIC_ENABLE_NEXT_AUTH:
|
|
321
|
+
NEXT_PUBLIC_ENABLE_NEXT_AUTH: process.env.NEXT_PUBLIC_ENABLE_NEXT_AUTH === '1',
|
|
316
322
|
NEXT_AUTH_SSO_PROVIDERS: process.env.NEXT_AUTH_SSO_PROVIDERS,
|
|
317
323
|
NEXT_AUTH_SECRET: process.env.NEXT_AUTH_SECRET,
|
|
318
324
|
NEXT_AUTH_DEBUG: !!process.env.NEXT_AUTH_DEBUG,
|
|
@@ -414,3 +420,18 @@ export const getAuthConfig = () => {
|
|
|
414
420
|
};
|
|
415
421
|
|
|
416
422
|
export const authEnv = getAuthConfig();
|
|
423
|
+
|
|
424
|
+
// Auth flags - use process.env directly for build-time dead code elimination
|
|
425
|
+
export const enableClerk =
|
|
426
|
+
process.env.NEXT_PUBLIC_ENABLE_CLERK_AUTH === '1'
|
|
427
|
+
? true
|
|
428
|
+
: !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
|
|
429
|
+
export const enableBetterAuth = process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1';
|
|
430
|
+
export const enableNextAuth = process.env.NEXT_PUBLIC_ENABLE_NEXT_AUTH === '1';
|
|
431
|
+
export const enableAuth = enableClerk || enableBetterAuth || enableNextAuth || false;
|
|
432
|
+
|
|
433
|
+
// Auth headers and constants
|
|
434
|
+
export const LOBE_CHAT_AUTH_HEADER = 'X-lobe-chat-auth';
|
|
435
|
+
export const LOBE_CHAT_OIDC_AUTH_HEADER = 'Oidc-Auth';
|
|
436
|
+
export const OAUTH_AUTHORIZED = 'X-oauth-authorized';
|
|
437
|
+
export const SECRET_XOR_KEY = 'LobeHub · LobeHub';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { EditorModal } from '@/features/EditorModal';
|
|
5
4
|
|
|
6
5
|
import { useConversationStore } from '../../../store';
|
|
7
6
|
|
|
@@ -11,40 +10,24 @@ export interface EditStateProps {
|
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
const EditState = memo<EditStateProps>(({ id, content }) => {
|
|
14
|
-
const { t } = useTranslation('common');
|
|
15
|
-
|
|
16
|
-
const text = useMemo(
|
|
17
|
-
() => ({
|
|
18
|
-
cancel: t('cancel'),
|
|
19
|
-
confirm: t('ok'),
|
|
20
|
-
edit: t('edit'),
|
|
21
|
-
}),
|
|
22
|
-
[],
|
|
23
|
-
);
|
|
24
|
-
|
|
25
13
|
const [toggleMessageEditing, updateMessageContent] = useConversationStore((s) => [
|
|
26
14
|
s.toggleMessageEditing,
|
|
27
15
|
s.modifyMessageContent,
|
|
28
16
|
]);
|
|
29
17
|
|
|
30
|
-
const onEditingChange = (value: string) => {
|
|
31
|
-
updateMessageContent(id, value);
|
|
32
|
-
toggleMessageEditing(id, false);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
18
|
return (
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
19
|
+
<EditorModal
|
|
20
|
+
onCancel={() => {
|
|
21
|
+
toggleMessageEditing(id, false);
|
|
22
|
+
}}
|
|
23
|
+
onConfirm={async (value) => {
|
|
24
|
+
if (!id) return;
|
|
25
|
+
await updateMessageContent(id, value);
|
|
26
|
+
toggleMessageEditing(id, false);
|
|
27
|
+
}}
|
|
28
|
+
open={!!id}
|
|
29
|
+
value={content ? String(content) : ''}
|
|
30
|
+
/>
|
|
48
31
|
);
|
|
49
32
|
});
|
|
50
33
|
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import type { AssistantContentBlock } from '@lobechat/types';
|
|
4
4
|
import isEqual from 'fast-deep-equal';
|
|
5
|
-
import
|
|
5
|
+
import dynamic from 'next/dynamic';
|
|
6
|
+
import { type MouseEventHandler, Suspense, memo, useCallback, useMemo } from 'react';
|
|
6
7
|
|
|
7
8
|
import { MESSAGE_ACTION_BAR_PORTAL_ATTRIBUTES } from '@/const/messageActionPortal';
|
|
8
9
|
import { ChatItem } from '@/features/Conversation/ChatItem';
|
|
@@ -21,9 +22,12 @@ import {
|
|
|
21
22
|
import FileListViewer from '../User/components/FileListViewer';
|
|
22
23
|
import Usage from '../components/Extras/Usage';
|
|
23
24
|
import MessageBranch from '../components/MessageBranch';
|
|
24
|
-
import EditState from './components/EditState';
|
|
25
25
|
import Group from './components/Group';
|
|
26
26
|
|
|
27
|
+
const EditState = dynamic(() => import('./components/EditState'), {
|
|
28
|
+
ssr: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
27
31
|
const actionBarHolder = (
|
|
28
32
|
<div
|
|
29
33
|
{...{ [MESSAGE_ACTION_BAR_PORTAL_ATTRIBUTES.assistantGroup]: '' }}
|
|
@@ -92,11 +96,6 @@ const GroupMessage = memo<GroupMessageProps>(({ id, index, disableEditing, isLat
|
|
|
92
96
|
}
|
|
93
97
|
}, [isInbox]);
|
|
94
98
|
|
|
95
|
-
// If editing, show edit state
|
|
96
|
-
if (editing && contentId) {
|
|
97
|
-
return <EditState content={lastAssistantMsg?.content} id={contentId} />;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
99
|
return (
|
|
101
100
|
<ChatItem
|
|
102
101
|
actions={
|
|
@@ -139,6 +138,9 @@ const GroupMessage = memo<GroupMessageProps>(({ id, index, disableEditing, isLat
|
|
|
139
138
|
{model && (
|
|
140
139
|
<Usage model={model} performance={performance} provider={provider!} usage={usage} />
|
|
141
140
|
)}
|
|
141
|
+
<Suspense fallback={null}>
|
|
142
|
+
{editing && contentId && <EditState content={lastAssistantMsg?.content} id={contentId} />}
|
|
143
|
+
</Suspense>
|
|
142
144
|
</ChatItem>
|
|
143
145
|
);
|
|
144
146
|
}, isEqual);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
IEditor,
|
|
2
3
|
ReactCodePlugin,
|
|
3
4
|
ReactCodemirrorPlugin,
|
|
4
5
|
ReactHRPlugin,
|
|
@@ -7,72 +8,52 @@ import {
|
|
|
7
8
|
ReactMathPlugin,
|
|
8
9
|
ReactTablePlugin,
|
|
9
10
|
} from '@lobehub/editor';
|
|
10
|
-
import { Editor
|
|
11
|
+
import { Editor } from '@lobehub/editor/react';
|
|
11
12
|
import { Flexbox } from '@lobehub/ui';
|
|
12
13
|
import { FC } from 'react';
|
|
13
14
|
|
|
14
15
|
import TypoBar from './Typobar';
|
|
15
16
|
|
|
16
17
|
interface EditorCanvasProps {
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
defaultValue?: string;
|
|
19
|
+
editor?: IEditor;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const EditorCanvas: FC<EditorCanvasProps> = ({
|
|
22
|
-
const editor = useEditor();
|
|
22
|
+
const EditorCanvas: FC<EditorCanvasProps> = ({ defaultValue, editor }) => {
|
|
23
23
|
return (
|
|
24
24
|
<>
|
|
25
25
|
<TypoBar editor={editor} />
|
|
26
26
|
<Flexbox
|
|
27
|
-
onClick={() => {
|
|
28
|
-
editor?.focus();
|
|
29
|
-
}}
|
|
30
27
|
padding={16}
|
|
31
28
|
style={{ cursor: 'text', maxHeight: '80vh', minHeight: '50vh', overflowY: 'auto' }}
|
|
32
29
|
>
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
<Editor
|
|
31
|
+
autoFocus
|
|
32
|
+
content={''}
|
|
33
|
+
editor={editor}
|
|
34
|
+
onInit={(editor) => {
|
|
35
|
+
if (!editor || !defaultValue) return;
|
|
36
|
+
try {
|
|
37
|
+
editor?.setDocument('markdown', defaultValue);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.error('setDocument error:', e);
|
|
40
|
+
}
|
|
37
41
|
}}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const newValue = editor.getDocument('markdown') as unknown as string;
|
|
54
|
-
onChange?.(newValue);
|
|
55
|
-
} catch (e) {
|
|
56
|
-
console.error('getDocument error:', e);
|
|
57
|
-
onChange?.('');
|
|
58
|
-
}
|
|
59
|
-
}}
|
|
60
|
-
plugins={[
|
|
61
|
-
ReactListPlugin,
|
|
62
|
-
ReactCodePlugin,
|
|
63
|
-
ReactCodemirrorPlugin,
|
|
64
|
-
ReactHRPlugin,
|
|
65
|
-
ReactLinkPlugin,
|
|
66
|
-
ReactTablePlugin,
|
|
67
|
-
ReactMathPlugin,
|
|
68
|
-
]}
|
|
69
|
-
style={{
|
|
70
|
-
paddingBottom: 120,
|
|
71
|
-
}}
|
|
72
|
-
type={'text'}
|
|
73
|
-
variant={'chat'}
|
|
74
|
-
/>
|
|
75
|
-
</div>
|
|
42
|
+
plugins={[
|
|
43
|
+
ReactListPlugin,
|
|
44
|
+
ReactCodePlugin,
|
|
45
|
+
ReactCodemirrorPlugin,
|
|
46
|
+
ReactHRPlugin,
|
|
47
|
+
ReactLinkPlugin,
|
|
48
|
+
ReactTablePlugin,
|
|
49
|
+
ReactMathPlugin,
|
|
50
|
+
]}
|
|
51
|
+
style={{
|
|
52
|
+
paddingBottom: 120,
|
|
53
|
+
}}
|
|
54
|
+
type={'text'}
|
|
55
|
+
variant={'chat'}
|
|
56
|
+
/>
|
|
76
57
|
</Flexbox>
|
|
77
58
|
</>
|
|
78
59
|
);
|
|
@@ -2,13 +2,15 @@ import { TextArea } from '@lobehub/ui';
|
|
|
2
2
|
import { FC } from 'react';
|
|
3
3
|
|
|
4
4
|
interface EditorCanvasProps {
|
|
5
|
+
defaultValue?: string;
|
|
5
6
|
onChange?: (value: string) => void;
|
|
6
7
|
value?: string;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
const EditorCanvas: FC<EditorCanvasProps> = ({ value, onChange }) => {
|
|
10
|
+
const EditorCanvas: FC<EditorCanvasProps> = ({ defaultValue, value, onChange }) => {
|
|
10
11
|
return (
|
|
11
12
|
<TextArea
|
|
13
|
+
defaultValue={defaultValue}
|
|
12
14
|
onChange={(e) => {
|
|
13
15
|
onChange?.(e.target.value);
|
|
14
16
|
}}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useEditor } from '@lobehub/editor/react';
|
|
1
2
|
import { Modal, ModalProps, createRawModal } from '@lobehub/ui';
|
|
2
3
|
import { memo, useState } from 'react';
|
|
3
4
|
import { useTranslation } from 'react-i18next';
|
|
@@ -18,8 +19,7 @@ export const EditorModal = memo<EditorModalProps>(({ value, onConfirm, ...rest }
|
|
|
18
19
|
const { t } = useTranslation('common');
|
|
19
20
|
const [v, setV] = useState(value);
|
|
20
21
|
const enableRichRender = useUserStore(labPreferSelectors.enableInputMarkdown);
|
|
21
|
-
|
|
22
|
-
const Canvas = enableRichRender ? EditorCanvas : TextareCanvas;
|
|
22
|
+
const editor = useEditor();
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<Modal
|
|
@@ -30,7 +30,13 @@ export const EditorModal = memo<EditorModalProps>(({ value, onConfirm, ...rest }
|
|
|
30
30
|
okText={t('ok')}
|
|
31
31
|
onOk={async () => {
|
|
32
32
|
setConfirmLoading(true);
|
|
33
|
-
|
|
33
|
+
let finalValue;
|
|
34
|
+
if (enableRichRender) {
|
|
35
|
+
finalValue = editor?.getDocument('markdown') as unknown as string;
|
|
36
|
+
} else {
|
|
37
|
+
finalValue = v;
|
|
38
|
+
}
|
|
39
|
+
await onConfirm?.(finalValue || '');
|
|
34
40
|
setConfirmLoading(false);
|
|
35
41
|
}}
|
|
36
42
|
styles={{
|
|
@@ -43,7 +49,11 @@ export const EditorModal = memo<EditorModalProps>(({ value, onConfirm, ...rest }
|
|
|
43
49
|
width={'min(90vw, 920px)'}
|
|
44
50
|
{...rest}
|
|
45
51
|
>
|
|
46
|
-
|
|
52
|
+
{enableRichRender ? (
|
|
53
|
+
<EditorCanvas defaultValue={value} editor={editor} />
|
|
54
|
+
) : (
|
|
55
|
+
<TextareCanvas defaultValue={value} onChange={(v) => setV(v)} value={v} />
|
|
56
|
+
)}
|
|
47
57
|
</Modal>
|
|
48
58
|
);
|
|
49
59
|
});
|