@lobehub/lobehub 2.0.0-next.131 → 2.0.0-next.132
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/docs/development/database-schema.dbml +1 -0
- package/package.json +1 -1
- package/packages/database/migrations/0051_add_market_into_user_settings.sql +1 -0
- package/packages/database/migrations/meta/0051_snapshot.json +8168 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/src/core/migrations.json +20 -33
- package/packages/database/src/schemas/user.ts +1 -0
- package/packages/model-bank/src/standard-parameters/index.ts +14 -14
- package/packages/types/src/user/settings/index.ts +4 -0
- package/packages/types/src/user/settings/market.ts +17 -0
- package/src/app/[variants]/(main)/chat/components/topic/features/Topic/TopicListContent/TopicItem/index.tsx +6 -1
- package/src/app/[variants]/(main)/chat/settings/features/SmartAgentActionButton/MarketPublishModal.tsx +28 -12
- package/src/config/modelProviders/cerebras.ts +3 -0
- package/src/hooks/useAgentOwnershipCheck.ts +12 -4
- package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +120 -1
- package/src/layout/AuthProvider/MarketAuth/types.ts +4 -1
|
@@ -357,6 +357,13 @@
|
|
|
357
357
|
"when": 1764303057060,
|
|
358
358
|
"tag": "0050_thread_and_user_id",
|
|
359
359
|
"breakpoints": true
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"idx": 51,
|
|
363
|
+
"version": "7",
|
|
364
|
+
"when": 1764335703306,
|
|
365
|
+
"tag": "0051_add_market_into_user_settings",
|
|
366
|
+
"breakpoints": true
|
|
360
367
|
}
|
|
361
368
|
],
|
|
362
369
|
"version": "6"
|
|
@@ -223,10 +223,7 @@
|
|
|
223
223
|
"hash": "9646161fa041354714f823d726af27247bcd6e60fa3be5698c0d69f337a5700b"
|
|
224
224
|
},
|
|
225
225
|
{
|
|
226
|
-
"sql": [
|
|
227
|
-
"DROP TABLE \"user_budgets\";",
|
|
228
|
-
"\nDROP TABLE \"user_subscriptions\";"
|
|
229
|
-
],
|
|
226
|
+
"sql": ["DROP TABLE \"user_budgets\";", "\nDROP TABLE \"user_subscriptions\";"],
|
|
230
227
|
"bps": true,
|
|
231
228
|
"folderMillis": 1729699958471,
|
|
232
229
|
"hash": "7dad43a2a25d1aec82124a4e53f8d82f8505c3073f23606c1dc5d2a4598eacf9"
|
|
@@ -298,9 +295,7 @@
|
|
|
298
295
|
"hash": "845a692ceabbfc3caf252a97d3e19a213bc0c433df2689900135f9cfded2cf49"
|
|
299
296
|
},
|
|
300
297
|
{
|
|
301
|
-
"sql": [
|
|
302
|
-
"ALTER TABLE \"messages\" ADD COLUMN \"reasoning\" jsonb;"
|
|
303
|
-
],
|
|
298
|
+
"sql": ["ALTER TABLE \"messages\" ADD COLUMN \"reasoning\" jsonb;"],
|
|
304
299
|
"bps": true,
|
|
305
300
|
"folderMillis": 1737609172353,
|
|
306
301
|
"hash": "2cb36ae4fcdd7b7064767e04bfbb36ae34518ff4bb1b39006f2dd394d1893868"
|
|
@@ -515,9 +510,7 @@
|
|
|
515
510
|
"hash": "a7ccf007fd185ff922823148d1eae6fafe652fc98d2fd2793f84a84f29e93cd1"
|
|
516
511
|
},
|
|
517
512
|
{
|
|
518
|
-
"sql": [
|
|
519
|
-
"ALTER TABLE \"ai_providers\" ADD COLUMN \"config\" jsonb;"
|
|
520
|
-
],
|
|
513
|
+
"sql": ["ALTER TABLE \"ai_providers\" ADD COLUMN \"config\" jsonb;"],
|
|
521
514
|
"bps": true,
|
|
522
515
|
"folderMillis": 1749309388370,
|
|
523
516
|
"hash": "39cea379f08ee4cb944875c0b67f7791387b508c2d47958bb4cd501ed1ef33eb"
|
|
@@ -635,9 +628,7 @@
|
|
|
635
628
|
"hash": "1ba9b1f74ea13348da98d6fcdad7867ab4316ed565bf75d84d160c526cdac14b"
|
|
636
629
|
},
|
|
637
630
|
{
|
|
638
|
-
"sql": [
|
|
639
|
-
"ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"virtual\" boolean DEFAULT false;"
|
|
640
|
-
],
|
|
631
|
+
"sql": ["ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"virtual\" boolean DEFAULT false;"],
|
|
641
632
|
"bps": true,
|
|
642
633
|
"folderMillis": 1759116400580,
|
|
643
634
|
"hash": "433ddae88e785f2db734e49a4c115eee93e60afe389f7919d66e5ba9aa159a37"
|
|
@@ -687,17 +678,13 @@
|
|
|
687
678
|
"hash": "4bdc6505797d7a33b622498c138cfd47f637239f6905e1c484cd01d9d5f21d6b"
|
|
688
679
|
},
|
|
689
680
|
{
|
|
690
|
-
"sql": [
|
|
691
|
-
"ALTER TABLE \"user_settings\" ADD COLUMN IF NOT EXISTS \"image\" jsonb;"
|
|
692
|
-
],
|
|
681
|
+
"sql": ["ALTER TABLE \"user_settings\" ADD COLUMN IF NOT EXISTS \"image\" jsonb;"],
|
|
693
682
|
"bps": true,
|
|
694
683
|
"folderMillis": 1760108430562,
|
|
695
684
|
"hash": "ce09b301abb80f6563abc2f526bdd20b4f69bae430f09ba2179b9e3bfec43067"
|
|
696
685
|
},
|
|
697
686
|
{
|
|
698
|
-
"sql": [
|
|
699
|
-
"ALTER TABLE \"documents\" ADD COLUMN IF NOT EXISTS \"editor_data\" jsonb;"
|
|
700
|
-
],
|
|
687
|
+
"sql": ["ALTER TABLE \"documents\" ADD COLUMN IF NOT EXISTS \"editor_data\" jsonb;"],
|
|
701
688
|
"bps": true,
|
|
702
689
|
"folderMillis": 1761554153406,
|
|
703
690
|
"hash": "bf2f21293e90e11cf60a784cf3ec219eafa95f7545d7d2f9d1449c0b0949599a"
|
|
@@ -777,17 +764,13 @@
|
|
|
777
764
|
"hash": "923ccbdf46c32be9a981dabd348e6923b4a365444241e9b8cc174bf5b914cbc5"
|
|
778
765
|
},
|
|
779
766
|
{
|
|
780
|
-
"sql": [
|
|
781
|
-
"ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"market_identifier\" text;\n"
|
|
782
|
-
],
|
|
767
|
+
"sql": ["ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"market_identifier\" text;\n"],
|
|
783
768
|
"bps": true,
|
|
784
769
|
"folderMillis": 1762870034882,
|
|
785
770
|
"hash": "4178aacb4b8892b7fd15d29209bbf9b1d1f9d7c406ba796f27542c0bcd919680"
|
|
786
771
|
},
|
|
787
772
|
{
|
|
788
|
-
"sql": [
|
|
789
|
-
"ALTER TABLE \"message_plugins\" ADD COLUMN IF NOT EXISTS \"intervention\" jsonb;\n"
|
|
790
|
-
],
|
|
773
|
+
"sql": ["ALTER TABLE \"message_plugins\" ADD COLUMN IF NOT EXISTS \"intervention\" jsonb;\n"],
|
|
791
774
|
"bps": true,
|
|
792
775
|
"folderMillis": 1762911968658,
|
|
793
776
|
"hash": "552a032cc0e595277232e70b5f9338658585bafe9481ae8346a5f322b673a68b"
|
|
@@ -816,9 +799,7 @@
|
|
|
816
799
|
"hash": "f823b521f4d25e5dc5ab238b372727d2d2d7f0aed27b5eabc8a9608ce4e50568"
|
|
817
800
|
},
|
|
818
801
|
{
|
|
819
|
-
"sql": [
|
|
820
|
-
"ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"editor_data\" jsonb;"
|
|
821
|
-
],
|
|
802
|
+
"sql": ["ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"editor_data\" jsonb;"],
|
|
822
803
|
"bps": true,
|
|
823
804
|
"folderMillis": 1764215503726,
|
|
824
805
|
"hash": "4188893a9083b3c7baebdbad0dd3f9d9400ede7584ca2394f5c64305dc9ec7b0"
|
|
@@ -848,14 +829,20 @@
|
|
|
848
829
|
"\nALTER TABLE \"threads\" ALTER COLUMN \"status\" DROP DEFAULT;",
|
|
849
830
|
"\nALTER TABLE \"threads\" ALTER COLUMN \"source_message_id\" DROP NOT NULL;",
|
|
850
831
|
"\nALTER TABLE \"nextauth_authenticators\" ADD CONSTRAINT \"nextauth_authenticators_user_id_credentialID_pk\" PRIMARY KEY(\"user_id\",\"credentialID\");",
|
|
851
|
-
"\nALTER TABLE \"threads\" ADD COLUMN \"content\" text;",
|
|
852
|
-
"\nALTER TABLE \"threads\" ADD COLUMN \"editor_data\" jsonb;",
|
|
832
|
+
"\nALTER TABLE \"threads\" ADD COLUMN IF NOT EXISTS \"content\" text;",
|
|
833
|
+
"\nALTER TABLE \"threads\" ADD COLUMN IF NOT EXISTS \"editor_data\" jsonb;",
|
|
853
834
|
"\nALTER TABLE \"nextauth_accounts\" ADD CONSTRAINT \"nextauth_accounts_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action;",
|
|
854
835
|
"\nALTER TABLE \"nextauth_authenticators\" ADD CONSTRAINT \"nextauth_authenticators_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action;",
|
|
855
|
-
"\nALTER TABLE \"nextauth_sessions\" ADD CONSTRAINT \"nextauth_sessions_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action
|
|
836
|
+
"\nALTER TABLE \"nextauth_sessions\" ADD CONSTRAINT \"nextauth_sessions_user_id_users_id_fk\" FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\") ON DELETE cascade ON UPDATE no action;\n"
|
|
856
837
|
],
|
|
857
838
|
"bps": true,
|
|
858
839
|
"folderMillis": 1764303057060,
|
|
859
|
-
"hash": "
|
|
840
|
+
"hash": "2c103eee82bdf329944fb622dd9c2b9f20df80eb54f23eb9254d2285de413099"
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
"sql": ["ALTER TABLE \"user_settings\" ADD COLUMN IF NOT EXISTS \"market\" jsonb;"],
|
|
844
|
+
"bps": true,
|
|
845
|
+
"folderMillis": 1764335703306,
|
|
846
|
+
"hash": "28c0d738c0b1fdf5fd871363be1a1477b4accbabdc140fe8dc6e9b339aae2c89"
|
|
860
847
|
}
|
|
861
|
-
]
|
|
848
|
+
]
|
|
@@ -46,6 +46,7 @@ export const userSettings = pgTable('user_settings', {
|
|
|
46
46
|
languageModel: jsonb('language_model'),
|
|
47
47
|
systemAgent: jsonb('system_agent'),
|
|
48
48
|
defaultAgent: jsonb('default_agent'),
|
|
49
|
+
market: jsonb('market'),
|
|
49
50
|
tool: jsonb('tool'),
|
|
50
51
|
image: jsonb('image'),
|
|
51
52
|
});
|
|
@@ -5,18 +5,18 @@ import { z } from 'zod';
|
|
|
5
5
|
export const MAX_SEED = 2 ** 31 - 1;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Default aspect ratio, used when the model doesn't support native aspect ratio
|
|
9
9
|
*/
|
|
10
10
|
export const DEFAULT_ASPECT_RATIO = '1:1';
|
|
11
11
|
|
|
12
12
|
export const PRESET_ASPECT_RATIOS = [
|
|
13
|
-
DEFAULT_ASPECT_RATIO, // '1:1' -
|
|
14
|
-
'16:9', //
|
|
15
|
-
'9:16', //
|
|
16
|
-
'4:3', //
|
|
17
|
-
'3:4', //
|
|
18
|
-
'3:2', //
|
|
19
|
-
'2:3', //
|
|
13
|
+
DEFAULT_ASPECT_RATIO, // '1:1' - Square, most commonly used
|
|
14
|
+
'16:9', // Modern monitors/TVs/video standard
|
|
15
|
+
'9:16', // Mobile portrait/short videos
|
|
16
|
+
'4:3', // Traditional monitors/photos
|
|
17
|
+
'3:4', // Traditional portrait photos
|
|
18
|
+
'3:2', // Classic photo ratio landscape
|
|
19
|
+
'2:3', // Classic photo ratio portrait
|
|
20
20
|
];
|
|
21
21
|
|
|
22
22
|
/**
|
|
@@ -52,10 +52,10 @@ export const CHAT_MODEL_IMAGE_GENERATION_PARAMS: ModelParamsSchema = {
|
|
|
52
52
|
prompt: { default: '' },
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
//
|
|
55
|
+
// Define top-level meta specification - flat structure
|
|
56
56
|
export const ModelParamsMetaSchema = z.object({
|
|
57
57
|
/**
|
|
58
|
-
* Prompt
|
|
58
|
+
* Prompt is the only parameter that every model has
|
|
59
59
|
*/
|
|
60
60
|
prompt: z.object({
|
|
61
61
|
default: z.string().optional().default(''),
|
|
@@ -213,7 +213,7 @@ export const ModelParamsMetaSchema = z.object({
|
|
|
213
213
|
})
|
|
214
214
|
.optional(),
|
|
215
215
|
});
|
|
216
|
-
//
|
|
216
|
+
// Export inferred type for use in defining objects
|
|
217
217
|
export type ModelParamsSchema = z.input<typeof ModelParamsMetaSchema>;
|
|
218
218
|
export type ModelParamsOutputSchema = z.output<typeof ModelParamsMetaSchema>;
|
|
219
219
|
export type ModelParamsKeys = Simplify<keyof ModelParamsOutputSchema>;
|
|
@@ -244,16 +244,16 @@ export type RuntimeImageGenParams = Pick<_StandardImageGenerationParameters, 'pr
|
|
|
244
244
|
export type RuntimeImageGenParamsKeys = keyof RuntimeImageGenParams;
|
|
245
245
|
export type RuntimeImageGenParamsValue = RuntimeImageGenParams[RuntimeImageGenParamsKeys];
|
|
246
246
|
|
|
247
|
-
//
|
|
247
|
+
// Validation function
|
|
248
248
|
export function validateModelParamsSchema(paramsSchema: unknown): ModelParamsOutputSchema {
|
|
249
249
|
return ModelParamsMetaSchema.parse(paramsSchema);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
/**
|
|
253
|
-
*
|
|
253
|
+
* Extract default values from parameter definition object
|
|
254
254
|
*/
|
|
255
255
|
export function extractDefaultValues(paramsSchema: ModelParamsSchema) {
|
|
256
|
-
//
|
|
256
|
+
// Some default values are obtained from ModelParamsMetaSchema
|
|
257
257
|
const schemaWithDefault = ModelParamsMetaSchema.parse(paramsSchema);
|
|
258
258
|
return Object.fromEntries(
|
|
259
259
|
Object.entries(schemaWithDefault).map(([key, value]) => {
|
|
@@ -5,6 +5,7 @@ import { UserGeneralConfig } from './general';
|
|
|
5
5
|
import { UserHotkeyConfig } from './hotkey';
|
|
6
6
|
import { UserImageConfig } from './image';
|
|
7
7
|
import { UserKeyVaults } from './keyVaults';
|
|
8
|
+
import { MarketAuthTokens } from './market';
|
|
8
9
|
import { UserModelProviderConfig } from './modelProvider';
|
|
9
10
|
import { UserSystemAgentConfig } from './systemAgent';
|
|
10
11
|
import { UserToolConfig } from './tool';
|
|
@@ -17,6 +18,7 @@ export * from './general';
|
|
|
17
18
|
export * from './hotkey';
|
|
18
19
|
export * from './image';
|
|
19
20
|
export * from './keyVaults';
|
|
21
|
+
export * from './market';
|
|
20
22
|
export * from './modelProvider';
|
|
21
23
|
export * from './sync';
|
|
22
24
|
export * from './systemAgent';
|
|
@@ -33,6 +35,7 @@ export interface UserSettings {
|
|
|
33
35
|
image: UserImageConfig;
|
|
34
36
|
keyVaults: UserKeyVaults;
|
|
35
37
|
languageModel: UserModelProviderConfig;
|
|
38
|
+
market?: MarketAuthTokens;
|
|
36
39
|
systemAgent: UserSystemAgentConfig;
|
|
37
40
|
tool: UserToolConfig;
|
|
38
41
|
tts: UserTTSConfig;
|
|
@@ -50,6 +53,7 @@ export const UserSettingsSchema = z
|
|
|
50
53
|
image: z.any().optional(),
|
|
51
54
|
keyVaults: z.any().optional(),
|
|
52
55
|
languageModel: z.any().optional(),
|
|
56
|
+
market: z.any().optional(),
|
|
53
57
|
systemAgent: z.any().optional(),
|
|
54
58
|
tool: z.any().optional(),
|
|
55
59
|
tts: z.any().optional(),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Market authentication tokens
|
|
3
|
+
*/
|
|
4
|
+
export interface MarketAuthTokens {
|
|
5
|
+
/**
|
|
6
|
+
* Access token for Market API requests
|
|
7
|
+
*/
|
|
8
|
+
accessToken?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Token expiration timestamp (milliseconds since epoch)
|
|
11
|
+
*/
|
|
12
|
+
expiresAt?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Refresh token for renewing access tokens
|
|
15
|
+
*/
|
|
16
|
+
refreshToken?: string;
|
|
17
|
+
}
|
|
@@ -53,7 +53,10 @@ export interface ConfigCellProps {
|
|
|
53
53
|
const TopicItem = memo<ConfigCellProps>(({ title, active, id, fav, threadId }) => {
|
|
54
54
|
const { styles, cx } = useStyles();
|
|
55
55
|
const toggleConfig = useGlobalStore((s) => s.toggleMobileTopic);
|
|
56
|
-
const [toggleTopic, editing] = useChatStore((s) => [
|
|
56
|
+
const [toggleTopic, editing] = useChatStore((s) => [
|
|
57
|
+
s.switchTopic,
|
|
58
|
+
s.topicRenamingId !== undefined && s.topicRenamingId === id,
|
|
59
|
+
]);
|
|
57
60
|
const activeId = useSessionStore((s) => s.activeId);
|
|
58
61
|
const [isHover, setHovering] = useState(false);
|
|
59
62
|
|
|
@@ -65,6 +68,8 @@ const TopicItem = memo<ConfigCellProps>(({ title, active, id, fav, threadId }) =
|
|
|
65
68
|
distribution={'space-between'}
|
|
66
69
|
horizontal
|
|
67
70
|
onClick={(e) => {
|
|
71
|
+
// Alt+Click should keep the current topic selection (reserved shortcut)
|
|
72
|
+
if (e.altKey) return;
|
|
68
73
|
// 重命名时不切换话题
|
|
69
74
|
if (editing) return;
|
|
70
75
|
// Ctrl/Cmd+点击在新窗口打开
|
|
@@ -40,7 +40,8 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
40
40
|
const isSubmit = action === 'submit';
|
|
41
41
|
const isUpload = action === 'upload';
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const marketAuth = useMarketAuth();
|
|
44
|
+
const { isAuthenticated } = marketAuth;
|
|
44
45
|
const meta = useSessionStore(sessionMetaSelectors.currentAgentMeta, isEqual);
|
|
45
46
|
const updateSessionMeta = useSessionStore((s) => s.updateSessionMeta);
|
|
46
47
|
|
|
@@ -74,7 +75,7 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
74
75
|
useEffect(() => {
|
|
75
76
|
if (!isUpload) return;
|
|
76
77
|
const marketIdentifier = meta?.marketIdentifier;
|
|
77
|
-
const accessToken =
|
|
78
|
+
const accessToken = marketAuth.getAccessToken();
|
|
78
79
|
if (!open || !isAuthenticated || !accessToken || !marketIdentifier) return;
|
|
79
80
|
|
|
80
81
|
let cancelled = false;
|
|
@@ -105,13 +106,14 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
105
106
|
return () => {
|
|
106
107
|
cancelled = true;
|
|
107
108
|
};
|
|
108
|
-
}, [isAuthenticated, isUpload,
|
|
109
|
+
}, [isAuthenticated, isUpload, marketAuth, meta?.marketIdentifier, open]);
|
|
109
110
|
|
|
110
111
|
const tokenUsage = useTokenCount(systemRole);
|
|
111
112
|
|
|
112
113
|
const handleSubmit = useCallback(
|
|
113
114
|
async (values: MarketPublishFormValues) => {
|
|
114
|
-
|
|
115
|
+
const accessToken = marketAuth.getAccessToken();
|
|
116
|
+
if (!isAuthenticated || !accessToken) {
|
|
115
117
|
message.error(t('marketPublish.modal.messages.notAuthenticated'));
|
|
116
118
|
return false;
|
|
117
119
|
}
|
|
@@ -126,12 +128,15 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
126
128
|
|
|
127
129
|
try {
|
|
128
130
|
message.loading({ content: loadingMessage, key: messageKey });
|
|
129
|
-
marketApiService.setAccessToken(
|
|
131
|
+
marketApiService.setAccessToken(accessToken);
|
|
130
132
|
|
|
131
133
|
if (isSubmit) {
|
|
132
134
|
identifier = values.identifier?.trim();
|
|
133
135
|
if (!identifier) {
|
|
134
|
-
message.error({
|
|
136
|
+
message.error({
|
|
137
|
+
content: t('marketPublish.modal.identifier.required'),
|
|
138
|
+
key: messageKey,
|
|
139
|
+
});
|
|
135
140
|
return false;
|
|
136
141
|
}
|
|
137
142
|
|
|
@@ -145,7 +150,10 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
145
150
|
await marketApiService.createAgent(createPayload as any);
|
|
146
151
|
}
|
|
147
152
|
} else if (!identifier) {
|
|
148
|
-
message.error({
|
|
153
|
+
message.error({
|
|
154
|
+
content: t('marketPublish.modal.messages.missingIdentifier'),
|
|
155
|
+
key: messageKey,
|
|
156
|
+
});
|
|
149
157
|
return false;
|
|
150
158
|
}
|
|
151
159
|
|
|
@@ -174,7 +182,7 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
174
182
|
if (typeof plugin === 'string') {
|
|
175
183
|
return plugin;
|
|
176
184
|
} else {
|
|
177
|
-
return null
|
|
185
|
+
return null;
|
|
178
186
|
}
|
|
179
187
|
}) || [],
|
|
180
188
|
systemRole: systemRole,
|
|
@@ -191,7 +199,9 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
191
199
|
} catch (versionError) {
|
|
192
200
|
const errorMessage = versionError instanceof Error ? versionError.message : '未知错误';
|
|
193
201
|
message.error({
|
|
194
|
-
content: t('marketPublish.modal.messages.createVersionFailed', {
|
|
202
|
+
content: t('marketPublish.modal.messages.createVersionFailed', {
|
|
203
|
+
message: errorMessage,
|
|
204
|
+
}),
|
|
195
205
|
key: messageKey,
|
|
196
206
|
});
|
|
197
207
|
return false;
|
|
@@ -210,7 +220,10 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
210
220
|
} catch (error) {
|
|
211
221
|
console.error('Market publish failed:', error);
|
|
212
222
|
const errorMessage = error instanceof Error ? error.message : '发布失败';
|
|
213
|
-
message.error({
|
|
223
|
+
message.error({
|
|
224
|
+
content: t('marketPublish.modal.messages.publishFailed', { message: errorMessage }),
|
|
225
|
+
key: messageKey,
|
|
226
|
+
});
|
|
214
227
|
return false;
|
|
215
228
|
}
|
|
216
229
|
},
|
|
@@ -223,12 +236,12 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
223
236
|
isAuthenticated,
|
|
224
237
|
isSubmit,
|
|
225
238
|
language,
|
|
239
|
+
marketAuth,
|
|
226
240
|
meta?.avatar,
|
|
227
241
|
meta?.description,
|
|
228
242
|
meta?.marketIdentifier,
|
|
229
243
|
meta?.tags,
|
|
230
244
|
meta?.title,
|
|
231
|
-
marketSession?.accessToken,
|
|
232
245
|
messageKey,
|
|
233
246
|
loadingMessage,
|
|
234
247
|
model,
|
|
@@ -271,7 +284,10 @@ const MarketPublishModal = memo<MarketPublishModalProps>(
|
|
|
271
284
|
placeholder={t('marketPublish.modal.identifier.placeholder')}
|
|
272
285
|
rules={[
|
|
273
286
|
{ message: t('marketPublish.modal.identifier.required'), required: true },
|
|
274
|
-
{
|
|
287
|
+
{
|
|
288
|
+
message: t('marketPublish.modal.identifier.patternError'),
|
|
289
|
+
pattern: /^[\da-z-]+$/,
|
|
290
|
+
},
|
|
275
291
|
{ max: 50, message: t('marketPublish.modal.identifier.lengthError'), min: 3 },
|
|
276
292
|
]}
|
|
277
293
|
/>
|
|
@@ -9,6 +9,9 @@ const Cerebras: ModelProviderCard = {
|
|
|
9
9
|
modelsUrl: 'https://inference-docs.cerebras.ai/models/overview',
|
|
10
10
|
name: 'Cerebras',
|
|
11
11
|
settings: {
|
|
12
|
+
proxyUrl: {
|
|
13
|
+
placeholder: 'https://api.cerebras.ai/v1',
|
|
14
|
+
},
|
|
12
15
|
sdkType: 'openai',
|
|
13
16
|
showModelFetcher: true,
|
|
14
17
|
},
|
|
@@ -99,10 +99,10 @@ export const checkOwnership = async ({
|
|
|
99
99
|
export const useAgentOwnershipCheck = (marketIdentifier?: string): AgentOwnershipResult => {
|
|
100
100
|
const [result, setResult] = useState<AgentOwnershipResult>({ isOwnAgent: null });
|
|
101
101
|
const marketAuth = useMarketAuth();
|
|
102
|
-
const {
|
|
102
|
+
const { isAuthenticated } = marketAuth;
|
|
103
103
|
|
|
104
104
|
useEffect(() => {
|
|
105
|
-
if (!marketIdentifier || !isAuthenticated
|
|
105
|
+
if (!marketIdentifier || !isAuthenticated) {
|
|
106
106
|
setResult({ isOwnAgent: false });
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
@@ -121,8 +121,16 @@ export const useAgentOwnershipCheck = (marketIdentifier?: string): AgentOwnershi
|
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// 优先从 DB 获取 access token,如果没有则从 session 获取
|
|
125
|
+
const accessToken = marketAuth.getAccessToken();
|
|
126
|
+
if (!accessToken) {
|
|
127
|
+
console.warn('[useAgentOwnershipCheck] No access token available');
|
|
128
|
+
setResult({ isOwnAgent: false });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
124
132
|
const isOwner = await checkOwnership({
|
|
125
|
-
accessToken
|
|
133
|
+
accessToken,
|
|
126
134
|
accountId: currentAccountId,
|
|
127
135
|
marketIdentifier,
|
|
128
136
|
});
|
|
@@ -137,7 +145,7 @@ export const useAgentOwnershipCheck = (marketIdentifier?: string): AgentOwnershi
|
|
|
137
145
|
};
|
|
138
146
|
|
|
139
147
|
runOwnershipCheck();
|
|
140
|
-
}, [marketIdentifier, isAuthenticated,
|
|
148
|
+
}, [marketIdentifier, isAuthenticated, marketAuth]);
|
|
141
149
|
|
|
142
150
|
return result;
|
|
143
151
|
};
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { ReactNode, createContext, useContext, useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { MARKET_OIDC_ENDPOINTS } from '@/services/_url';
|
|
6
|
+
import { useUserStore } from '@/store/user';
|
|
7
|
+
import { settingsSelectors } from '@/store/user/slices/settings/selectors/settings';
|
|
6
8
|
|
|
7
9
|
import { MarketAuthError } from './errors';
|
|
8
10
|
import { MarketOIDC } from './oidc';
|
|
@@ -86,6 +88,71 @@ const fetchUserInfo = async (accessToken: string): Promise<MarketUserInfo | null
|
|
|
86
88
|
}
|
|
87
89
|
};
|
|
88
90
|
|
|
91
|
+
/**
|
|
92
|
+
* 从 DB 获取 market tokens
|
|
93
|
+
*/
|
|
94
|
+
const getMarketTokensFromDB = () => {
|
|
95
|
+
const settings = settingsSelectors.currentSettings(useUserStore.getState());
|
|
96
|
+
return settings.market;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 存储 market tokens 到 DB
|
|
101
|
+
*/
|
|
102
|
+
const saveMarketTokensToDB = async (
|
|
103
|
+
accessToken: string,
|
|
104
|
+
refreshToken?: string,
|
|
105
|
+
expiresAt?: number,
|
|
106
|
+
) => {
|
|
107
|
+
console.log('[MarketAuth] Saving tokens to DB');
|
|
108
|
+
try {
|
|
109
|
+
await useUserStore.getState().setSettings({
|
|
110
|
+
market: {
|
|
111
|
+
accessToken,
|
|
112
|
+
expiresAt,
|
|
113
|
+
refreshToken,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
console.log('[MarketAuth] Tokens saved to DB successfully');
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('[MarketAuth] Failed to save tokens to DB:', error);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 清除 DB 中的 market tokens
|
|
124
|
+
*/
|
|
125
|
+
const clearMarketTokensFromDB = async () => {
|
|
126
|
+
console.log('[MarketAuth] Clearing tokens from DB');
|
|
127
|
+
try {
|
|
128
|
+
await useUserStore.getState().setSettings({
|
|
129
|
+
market: {
|
|
130
|
+
accessToken: undefined,
|
|
131
|
+
expiresAt: undefined,
|
|
132
|
+
refreshToken: undefined,
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
console.log('[MarketAuth] Tokens cleared from DB successfully');
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error('[MarketAuth] Failed to clear tokens from DB:', error);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 获取 refresh token(优先从 DB 获取)
|
|
143
|
+
*/
|
|
144
|
+
const getRefreshToken = (): string | null => {
|
|
145
|
+
// 优先从 DB 获取
|
|
146
|
+
const dbTokens = getMarketTokensFromDB();
|
|
147
|
+
if (dbTokens?.refreshToken) {
|
|
148
|
+
console.log('[MarketAuth] Retrieved refresh token from DB');
|
|
149
|
+
return dbTokens.refreshToken;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log('[MarketAuth] No refresh token found');
|
|
153
|
+
return null;
|
|
154
|
+
};
|
|
155
|
+
|
|
89
156
|
/**
|
|
90
157
|
* 刷新令牌(暂时简化,后续可以实现 refresh token 逻辑)
|
|
91
158
|
*/
|
|
@@ -234,6 +301,13 @@ export const MarketAuthProvider = ({ children, isDesktop }: MarketAuthProviderPr
|
|
|
234
301
|
sessionStorage.setItem('market_user_info', JSON.stringify(userInfo));
|
|
235
302
|
}
|
|
236
303
|
|
|
304
|
+
// 存储 tokens 到 DB
|
|
305
|
+
await saveMarketTokensToDB(
|
|
306
|
+
tokenResponse.accessToken,
|
|
307
|
+
tokenResponse.refreshToken,
|
|
308
|
+
newSession.expiresAt,
|
|
309
|
+
);
|
|
310
|
+
|
|
237
311
|
setSession(newSession);
|
|
238
312
|
setStatus('authenticated');
|
|
239
313
|
|
|
@@ -249,12 +323,14 @@ export const MarketAuthProvider = ({ children, isDesktop }: MarketAuthProviderPr
|
|
|
249
323
|
/**
|
|
250
324
|
* 登出方法
|
|
251
325
|
*/
|
|
252
|
-
const signOut = () => {
|
|
326
|
+
const signOut = async () => {
|
|
253
327
|
setSession(null);
|
|
254
328
|
setStatus('unauthenticated');
|
|
255
329
|
removeTokenFromCookie();
|
|
256
330
|
sessionStorage.removeItem('market_auth_session');
|
|
257
331
|
sessionStorage.removeItem('market_user_info');
|
|
332
|
+
// 清除 DB 中的 tokens
|
|
333
|
+
await clearMarketTokensFromDB();
|
|
258
334
|
};
|
|
259
335
|
|
|
260
336
|
/**
|
|
@@ -279,6 +355,40 @@ export const MarketAuthProvider = ({ children, isDesktop }: MarketAuthProviderPr
|
|
|
279
355
|
return null;
|
|
280
356
|
};
|
|
281
357
|
|
|
358
|
+
/**
|
|
359
|
+
* 获取 access token(优先从 DB 获取,否则从 session 获取)
|
|
360
|
+
*/
|
|
361
|
+
const getAccessToken = (): string | null => {
|
|
362
|
+
// 优先从 DB 获取
|
|
363
|
+
const dbTokens = getMarketTokensFromDB();
|
|
364
|
+
if (dbTokens?.accessToken) {
|
|
365
|
+
console.log('[MarketAuth] Retrieved access token from DB');
|
|
366
|
+
return dbTokens.accessToken;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 如果 DB 中没有,从 session 获取
|
|
370
|
+
if (session?.accessToken) {
|
|
371
|
+
console.log('[MarketAuth] Retrieved access token from session');
|
|
372
|
+
return session.accessToken;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// 如果 session 中也没有,尝试从 sessionStorage 获取
|
|
376
|
+
try {
|
|
377
|
+
const sessionData = sessionStorage.getItem('market_auth_session');
|
|
378
|
+
if (sessionData) {
|
|
379
|
+
const parsedSession = JSON.parse(sessionData) as MarketAuthSession;
|
|
380
|
+
if (parsedSession.accessToken) {
|
|
381
|
+
console.log('[MarketAuth] Retrieved access token from sessionStorage');
|
|
382
|
+
return parsedSession.accessToken;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error('[MarketAuth] Failed to get access token from sessionStorage:', error);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return null;
|
|
390
|
+
};
|
|
391
|
+
|
|
282
392
|
/**
|
|
283
393
|
* 初始化时恢复会话
|
|
284
394
|
*/
|
|
@@ -324,6 +434,13 @@ export const MarketAuthProvider = ({ children, isDesktop }: MarketAuthProviderPr
|
|
|
324
434
|
sessionStorage.setItem('market_user_info', JSON.stringify(userInfo));
|
|
325
435
|
}
|
|
326
436
|
|
|
437
|
+
// 存储 tokens 到 DB
|
|
438
|
+
await saveMarketTokensToDB(
|
|
439
|
+
tokenResponse.accessToken,
|
|
440
|
+
tokenResponse.refreshToken,
|
|
441
|
+
newSession.expiresAt,
|
|
442
|
+
);
|
|
443
|
+
|
|
327
444
|
setSession(newSession);
|
|
328
445
|
setStatus('authenticated');
|
|
329
446
|
|
|
@@ -339,7 +456,9 @@ export const MarketAuthProvider = ({ children, isDesktop }: MarketAuthProviderPr
|
|
|
339
456
|
}, [shouldReauthorize, oidcClient]);
|
|
340
457
|
|
|
341
458
|
const contextValue: MarketAuthContextType = {
|
|
459
|
+
getAccessToken,
|
|
342
460
|
getCurrentUserInfo,
|
|
461
|
+
getRefreshToken,
|
|
343
462
|
isAuthenticated: status === 'authenticated',
|
|
344
463
|
isLoading: status === 'loading',
|
|
345
464
|
refreshToken,
|
|
@@ -36,10 +36,12 @@ export interface MarketAuthState {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export interface MarketAuthContextType extends MarketAuthState {
|
|
39
|
+
getAccessToken: () => string | null;
|
|
39
40
|
getCurrentUserInfo: () => MarketUserInfo | null;
|
|
41
|
+
getRefreshToken: () => string | null;
|
|
40
42
|
refreshToken: () => Promise<boolean>;
|
|
41
43
|
signIn: () => Promise<number | null>;
|
|
42
|
-
signOut: () => void
|
|
44
|
+
signOut: () => Promise<void>;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
export interface OIDCConfig {
|
|
@@ -59,6 +61,7 @@ export interface TokenResponse {
|
|
|
59
61
|
accessToken: string;
|
|
60
62
|
expiresIn: number;
|
|
61
63
|
idToken?: string;
|
|
64
|
+
refreshToken?: string;
|
|
62
65
|
scope: string;
|
|
63
66
|
tokenType: string;
|
|
64
67
|
}
|