@lobehub/chat 1.105.0 → 1.105.2
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 +60 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/auth.json +54 -0
- package/locales/bg-BG/auth.json +54 -0
- package/locales/de-DE/auth.json +54 -0
- package/locales/en-US/auth.json +54 -0
- package/locales/es-ES/auth.json +54 -0
- package/locales/fa-IR/auth.json +54 -0
- package/locales/fr-FR/auth.json +54 -0
- package/locales/it-IT/auth.json +54 -0
- package/locales/ja-JP/auth.json +54 -0
- package/locales/ko-KR/auth.json +54 -0
- package/locales/nl-NL/auth.json +54 -0
- package/locales/pl-PL/auth.json +54 -0
- package/locales/pt-BR/auth.json +54 -0
- package/locales/ru-RU/auth.json +54 -0
- package/locales/tr-TR/auth.json +54 -0
- package/locales/vi-VN/auth.json +54 -0
- package/locales/zh-CN/auth.json +54 -0
- package/locales/zh-TW/auth.json +54 -0
- package/package.json +2 -2
- package/src/app/(backend)/middleware/auth/index.test.ts +5 -5
- package/src/app/(backend)/middleware/auth/index.ts +6 -6
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +11 -9
- package/src/app/(backend)/webapi/plugin/gateway/route.ts +2 -2
- package/src/app/sitemap.tsx +1 -10
- package/src/config/aiModels/giteeai.ts +269 -2
- package/src/config/aiModels/qwen.ts +207 -2
- package/src/config/aiModels/siliconcloud.ts +24 -2
- package/src/config/aiModels/stepfun.ts +67 -2
- package/src/config/aiModels/volcengine.ts +56 -2
- package/src/config/aiModels/wenxin.ts +62 -2
- package/src/config/aiModels/xai.ts +19 -2
- package/src/const/auth.ts +2 -3
- package/src/libs/model-runtime/ModelRuntime.test.ts +3 -3
- package/src/libs/model-runtime/qwen/createImage.ts +29 -9
- package/src/libs/trpc/async/context.ts +3 -3
- package/src/libs/trpc/edge/context.ts +7 -2
- package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +4 -4
- package/src/libs/trpc/edge/middleware/jwtPayload.ts +2 -2
- package/src/libs/trpc/lambda/context.ts +2 -2
- package/src/libs/trpc/lambda/middleware/keyVaults.ts +2 -2
- package/src/server/modules/AgentRuntime/index.test.ts +28 -25
- package/src/server/modules/AgentRuntime/index.ts +3 -3
- package/src/server/routers/async/caller.ts +2 -2
- package/src/server/routers/lambda/market/index.ts +0 -14
- package/src/server/routers/tools/search.test.ts +2 -2
- package/src/server/services/chunk/index.ts +3 -3
- package/src/server/services/discover/index.ts +0 -13
- package/src/server/sitemap.test.ts +0 -52
- package/src/server/sitemap.ts +1 -38
- package/src/services/_auth.ts +3 -3
- package/src/services/discover.ts +0 -4
- package/src/store/discover/slices/mcp/action.ts +0 -8
- package/src/utils/client/xor-obfuscation.test.ts +370 -0
- package/src/utils/client/xor-obfuscation.ts +39 -0
- package/src/utils/server/xor.test.ts +123 -0
- package/src/utils/server/xor.ts +42 -0
- package/src/utils/jwt.test.ts +0 -27
- package/src/utils/jwt.ts +0 -37
- package/src/utils/server/jwt.test.ts +0 -62
- package/src/utils/server/jwt.ts +0 -28
@@ -1,7 +1,7 @@
|
|
1
1
|
// @vitest-environment node
|
2
2
|
import { describe, expect, it, vi } from 'vitest';
|
3
3
|
|
4
|
-
import {
|
4
|
+
import { ClientSecretPayload } from '@/const/auth';
|
5
5
|
import {
|
6
6
|
LobeAnthropicAI,
|
7
7
|
LobeAzureOpenAI,
|
@@ -67,7 +67,10 @@ vi.mock('@/config/llm', () => ({
|
|
67
67
|
describe('initAgentRuntimeWithUserPayload method', () => {
|
68
68
|
describe('should initialize with options correctly', () => {
|
69
69
|
it('OpenAI provider: with apikey and endpoint', async () => {
|
70
|
-
const jwtPayload:
|
70
|
+
const jwtPayload: ClientSecretPayload = {
|
71
|
+
apiKey: 'user-openai-key',
|
72
|
+
baseURL: 'user-endpoint',
|
73
|
+
};
|
71
74
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenAI, jwtPayload);
|
72
75
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
73
76
|
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
@@ -75,7 +78,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
75
78
|
});
|
76
79
|
|
77
80
|
it('Azure AI provider: with apikey, endpoint and apiversion', async () => {
|
78
|
-
const jwtPayload:
|
81
|
+
const jwtPayload: ClientSecretPayload = {
|
79
82
|
apiKey: 'user-azure-key',
|
80
83
|
baseURL: 'user-azure-endpoint',
|
81
84
|
azureApiVersion: '2024-06-01',
|
@@ -87,35 +90,35 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
87
90
|
});
|
88
91
|
|
89
92
|
it('ZhiPu AI provider: with apikey', async () => {
|
90
|
-
const jwtPayload:
|
93
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'zhipu.user-key' };
|
91
94
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.ZhiPu, jwtPayload);
|
92
95
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
93
96
|
expect(runtime['_runtime']).toBeInstanceOf(LobeZhipuAI);
|
94
97
|
});
|
95
98
|
|
96
99
|
it('Google provider: with apikey', async () => {
|
97
|
-
const jwtPayload:
|
100
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-google-key' };
|
98
101
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Google, jwtPayload);
|
99
102
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
100
103
|
expect(runtime['_runtime']).toBeInstanceOf(LobeGoogleAI);
|
101
104
|
});
|
102
105
|
|
103
106
|
it('Moonshot AI provider: with apikey', async () => {
|
104
|
-
const jwtPayload:
|
107
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-moonshot-key' };
|
105
108
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Moonshot, jwtPayload);
|
106
109
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
107
110
|
expect(runtime['_runtime']).toBeInstanceOf(LobeMoonshotAI);
|
108
111
|
});
|
109
112
|
|
110
113
|
it('Qwen AI provider: with apikey', async () => {
|
111
|
-
const jwtPayload:
|
114
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-qwen-key' };
|
112
115
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Qwen, jwtPayload);
|
113
116
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
114
117
|
expect(runtime['_runtime']).toBeInstanceOf(LobeQwenAI);
|
115
118
|
});
|
116
119
|
|
117
120
|
it('Bedrock AI provider: with apikey, awsAccessKeyId, awsSecretAccessKey, awsRegion', async () => {
|
118
|
-
const jwtPayload:
|
121
|
+
const jwtPayload: ClientSecretPayload = {
|
119
122
|
apiKey: 'user-bedrock-key',
|
120
123
|
awsAccessKeyId: 'user-aws-id',
|
121
124
|
awsSecretAccessKey: 'user-aws-secret',
|
@@ -127,7 +130,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
127
130
|
});
|
128
131
|
|
129
132
|
it('Ollama provider: with endpoint', async () => {
|
130
|
-
const jwtPayload:
|
133
|
+
const jwtPayload: ClientSecretPayload = { baseURL: 'http://user-ollama-url' };
|
131
134
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Ollama, jwtPayload);
|
132
135
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
133
136
|
expect(runtime['_runtime']).toBeInstanceOf(LobeOllamaAI);
|
@@ -135,49 +138,49 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
135
138
|
});
|
136
139
|
|
137
140
|
it('Perplexity AI provider: with apikey', async () => {
|
138
|
-
const jwtPayload:
|
141
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-perplexity-key' };
|
139
142
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Perplexity, jwtPayload);
|
140
143
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
141
144
|
expect(runtime['_runtime']).toBeInstanceOf(LobePerplexityAI);
|
142
145
|
});
|
143
146
|
|
144
147
|
it('Anthropic AI provider: with apikey', async () => {
|
145
|
-
const jwtPayload:
|
148
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-anthropic-key' };
|
146
149
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Anthropic, jwtPayload);
|
147
150
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
148
151
|
expect(runtime['_runtime']).toBeInstanceOf(LobeAnthropicAI);
|
149
152
|
});
|
150
153
|
|
151
154
|
it('Minimax AI provider: with apikey', async () => {
|
152
|
-
const jwtPayload:
|
155
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-minimax-key' };
|
153
156
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Minimax, jwtPayload);
|
154
157
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
155
158
|
expect(runtime['_runtime']).toBeInstanceOf(LobeMinimaxAI);
|
156
159
|
});
|
157
160
|
|
158
161
|
it('Mistral AI provider: with apikey', async () => {
|
159
|
-
const jwtPayload:
|
162
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-mistral-key' };
|
160
163
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Mistral, jwtPayload);
|
161
164
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
162
165
|
expect(runtime['_runtime']).toBeInstanceOf(LobeMistralAI);
|
163
166
|
});
|
164
167
|
|
165
168
|
it('OpenRouter AI provider: with apikey', async () => {
|
166
|
-
const jwtPayload:
|
169
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-openrouter-key' };
|
167
170
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenRouter, jwtPayload);
|
168
171
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
169
172
|
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenRouterAI);
|
170
173
|
});
|
171
174
|
|
172
175
|
it('DeepSeek AI provider: with apikey', async () => {
|
173
|
-
const jwtPayload:
|
176
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-deepseek-key' };
|
174
177
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.DeepSeek, jwtPayload);
|
175
178
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
176
179
|
expect(runtime['_runtime']).toBeInstanceOf(LobeDeepSeekAI);
|
177
180
|
});
|
178
181
|
|
179
182
|
it('Together AI provider: with apikey', async () => {
|
180
|
-
const jwtPayload:
|
183
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-togetherai-key' };
|
181
184
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.TogetherAI, jwtPayload);
|
182
185
|
expect(runtime).toBeInstanceOf(AgentRuntime);
|
183
186
|
expect(runtime['_runtime']).toBeInstanceOf(LobeTogetherAI);
|
@@ -205,7 +208,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
205
208
|
});
|
206
209
|
|
207
210
|
it('Unknown Provider: with apikey and endpoint, should initialize to OpenAi', async () => {
|
208
|
-
const jwtPayload:
|
211
|
+
const jwtPayload: ClientSecretPayload = {
|
209
212
|
apiKey: 'user-unknown-key',
|
210
213
|
baseURL: 'user-unknown-endpoint',
|
211
214
|
};
|
@@ -218,13 +221,13 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
218
221
|
|
219
222
|
describe('should initialize without some options', () => {
|
220
223
|
it('OpenAI provider: without apikey', async () => {
|
221
|
-
const jwtPayload:
|
224
|
+
const jwtPayload: ClientSecretPayload = {};
|
222
225
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenAI, jwtPayload);
|
223
226
|
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
224
227
|
});
|
225
228
|
|
226
229
|
it('Azure AI Provider: without apikey', async () => {
|
227
|
-
const jwtPayload:
|
230
|
+
const jwtPayload: ClientSecretPayload = {
|
228
231
|
azureApiVersion: 'test-azure-api-version',
|
229
232
|
};
|
230
233
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Azure, jwtPayload);
|
@@ -233,7 +236,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
233
236
|
});
|
234
237
|
|
235
238
|
it('ZhiPu AI provider: without apikey', async () => {
|
236
|
-
const jwtPayload:
|
239
|
+
const jwtPayload: ClientSecretPayload = {};
|
237
240
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.ZhiPu, jwtPayload);
|
238
241
|
|
239
242
|
// 假设 LobeZhipuAI 是 ZhiPu 提供者的实现类
|
@@ -248,7 +251,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
248
251
|
});
|
249
252
|
|
250
253
|
it('Moonshot AI provider: without apikey', async () => {
|
251
|
-
const jwtPayload:
|
254
|
+
const jwtPayload: ClientSecretPayload = {};
|
252
255
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Moonshot, jwtPayload);
|
253
256
|
|
254
257
|
// 假设 LobeMoonshotAI 是 Moonshot 提供者的实现类
|
@@ -256,7 +259,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
256
259
|
});
|
257
260
|
|
258
261
|
it('Qwen AI provider: without apikey', async () => {
|
259
|
-
const jwtPayload:
|
262
|
+
const jwtPayload: ClientSecretPayload = {};
|
260
263
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Qwen, jwtPayload);
|
261
264
|
|
262
265
|
// 假设 LobeQwenAI 是 Qwen 提供者的实现类
|
@@ -264,7 +267,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
264
267
|
});
|
265
268
|
|
266
269
|
it('Qwen AI provider: without endpoint', async () => {
|
267
|
-
const jwtPayload:
|
270
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-qwen-key' };
|
268
271
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Qwen, jwtPayload);
|
269
272
|
|
270
273
|
// 假设 LobeQwenAI 是 Qwen 提供者的实现类
|
@@ -356,7 +359,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
356
359
|
it('OpenAI provider: without apikey with OPENAI_PROXY_URL', async () => {
|
357
360
|
process.env.OPENAI_PROXY_URL = 'https://proxy.example.com/v1';
|
358
361
|
|
359
|
-
const jwtPayload:
|
362
|
+
const jwtPayload: ClientSecretPayload = {};
|
360
363
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.OpenAI, jwtPayload);
|
361
364
|
expect(runtime['_runtime']).toBeInstanceOf(LobeOpenAI);
|
362
365
|
// 应返回 OPENAI_PROXY_URL
|
@@ -366,7 +369,7 @@ describe('initAgentRuntimeWithUserPayload method', () => {
|
|
366
369
|
it('Qwen AI provider: without apiKey and endpoint with OPENAI_PROXY_URL', async () => {
|
367
370
|
process.env.OPENAI_PROXY_URL = 'https://proxy.example.com/v1';
|
368
371
|
|
369
|
-
const jwtPayload:
|
372
|
+
const jwtPayload: ClientSecretPayload = {};
|
370
373
|
const runtime = await initAgentRuntimeWithUserPayload(ModelProvider.Qwen, jwtPayload);
|
371
374
|
|
372
375
|
// 假设 LobeQwenAI 是 Qwen 提供者的实现类
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { getLLMConfig } from '@/config/llm';
|
2
|
-
import {
|
2
|
+
import { ClientSecretPayload } from '@/const/auth';
|
3
3
|
import { AgentRuntime, ModelProvider } from '@/libs/model-runtime';
|
4
4
|
|
5
5
|
import apiKeyManager from './apiKeyManager';
|
@@ -14,7 +14,7 @@ export * from './trace';
|
|
14
14
|
* @param payload - The JWT payload.
|
15
15
|
* @returns The options object.
|
16
16
|
*/
|
17
|
-
const getParamsFromPayload = (provider: string, payload:
|
17
|
+
const getParamsFromPayload = (provider: string, payload: ClientSecretPayload) => {
|
18
18
|
const llmConfig = getLLMConfig() as Record<string, any>;
|
19
19
|
|
20
20
|
switch (provider) {
|
@@ -115,7 +115,7 @@ const getParamsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
115
115
|
*/
|
116
116
|
export const initAgentRuntimeWithUserPayload = (
|
117
117
|
provider: string,
|
118
|
-
payload:
|
118
|
+
payload: ClientSecretPayload,
|
119
119
|
params: any = {},
|
120
120
|
) => {
|
121
121
|
return AgentRuntime.initializeWithProvider(provider, {
|
@@ -3,7 +3,7 @@ import superjson from 'superjson';
|
|
3
3
|
import urlJoin from 'url-join';
|
4
4
|
|
5
5
|
import { serverDBEnv } from '@/config/db';
|
6
|
-
import {
|
6
|
+
import { ClientSecretPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
|
7
7
|
import { isDesktop } from '@/const/version';
|
8
8
|
import { appEnv } from '@/envs/app';
|
9
9
|
import { createAsyncCallerFactory } from '@/libs/trpc/async';
|
@@ -13,7 +13,7 @@ import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
|
13
13
|
import { asyncRouter } from './index';
|
14
14
|
import type { AsyncRouter } from './index';
|
15
15
|
|
16
|
-
export const createAsyncServerClient = async (userId: string, payload:
|
16
|
+
export const createAsyncServerClient = async (userId: string, payload: ClientSecretPayload) => {
|
17
17
|
const gateKeeper = await KeyVaultsGateKeeper.initWithEnvKey();
|
18
18
|
const headers: Record<string, string> = {
|
19
19
|
Authorization: `Bearer ${serverDBEnv.KEY_VAULTS_SECRET}`,
|
@@ -173,20 +173,6 @@ export const marketRouter = router({
|
|
173
173
|
}
|
174
174
|
}),
|
175
175
|
|
176
|
-
getMcpIdentifiers: marketProcedure.query(async ({ ctx }) => {
|
177
|
-
log('getMcpIdentifiers called');
|
178
|
-
|
179
|
-
try {
|
180
|
-
return await ctx.discoverService.getMcpIdentifiers();
|
181
|
-
} catch (error) {
|
182
|
-
log('Error fetching mcp identifiers: %O', error);
|
183
|
-
throw new TRPCError({
|
184
|
-
code: 'INTERNAL_SERVER_ERROR',
|
185
|
-
message: 'Failed to fetch mcp identifiers',
|
186
|
-
});
|
187
|
-
}
|
188
|
-
}),
|
189
|
-
|
190
176
|
getMcpList: marketProcedure
|
191
177
|
.input(
|
192
178
|
z
|
@@ -9,8 +9,8 @@ import { SEARCH_SEARXNG_NOT_CONFIG } from '@/types/tool/search';
|
|
9
9
|
import { searchRouter } from './search';
|
10
10
|
|
11
11
|
// Mock JWT verification
|
12
|
-
vi.mock('@/utils/server/
|
13
|
-
|
12
|
+
vi.mock('@/utils/server/xor', () => ({
|
13
|
+
getXorPayload: vi.fn().mockReturnValue({ userId: '1' }),
|
14
14
|
}));
|
15
15
|
|
16
16
|
vi.mock('@lobechat/web-crawler', () => ({
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { ClientSecretPayload } from '@/const/auth';
|
2
2
|
import { AsyncTaskModel } from '@/database/models/asyncTask';
|
3
3
|
import { FileModel } from '@/database/models/file';
|
4
4
|
import { serverDB } from '@/database/server';
|
@@ -30,7 +30,7 @@ export class ChunkService {
|
|
30
30
|
return this.chunkClient.chunkContent(params);
|
31
31
|
}
|
32
32
|
|
33
|
-
async asyncEmbeddingFileChunks(fileId: string, payload:
|
33
|
+
async asyncEmbeddingFileChunks(fileId: string, payload: ClientSecretPayload) {
|
34
34
|
const result = await this.fileModel.findById(fileId);
|
35
35
|
|
36
36
|
if (!result) return;
|
@@ -66,7 +66,7 @@ export class ChunkService {
|
|
66
66
|
/**
|
67
67
|
* parse file to chunks with async task
|
68
68
|
*/
|
69
|
-
async asyncParseFileToChunks(fileId: string, payload:
|
69
|
+
async asyncParseFileToChunks(fileId: string, payload: ClientSecretPayload, skipExist?: boolean) {
|
70
70
|
const result = await this.fileModel.findById(fileId);
|
71
71
|
|
72
72
|
if (!result) return;
|
@@ -462,19 +462,6 @@ export class DiscoverService {
|
|
462
462
|
return result;
|
463
463
|
};
|
464
464
|
|
465
|
-
getMcpIdentifiers = async (): Promise<IdentifiersResponse> => {
|
466
|
-
log('getMcpIdentifiers: fetching identifiers');
|
467
|
-
const result = await this.market.plugins.getPublishedIdentifiers({
|
468
|
-
cache: 'force-cache',
|
469
|
-
next: {
|
470
|
-
revalidate: CacheRevalidate.List,
|
471
|
-
tags: [CacheTag.Discover, CacheTag.MCP],
|
472
|
-
},
|
473
|
-
});
|
474
|
-
log('getMcpIdentifiers: returning %d identifiers', result.length);
|
475
|
-
return result;
|
476
|
-
};
|
477
|
-
|
478
465
|
getMcpList = async (params: McpQueryParams = {}): Promise<McpListResponse> => {
|
479
466
|
log('getMcpList: params=%O', params);
|
480
467
|
const { locale } = params;
|
@@ -13,7 +13,6 @@ describe('Sitemap', () => {
|
|
13
13
|
// Mock the page count methods to return specific values for testing
|
14
14
|
vi.spyOn(sitemap, 'getPluginPageCount').mockResolvedValue(2);
|
15
15
|
vi.spyOn(sitemap, 'getAssistantPageCount').mockResolvedValue(3);
|
16
|
-
vi.spyOn(sitemap, 'getMcpPageCount').mockResolvedValue(1);
|
17
16
|
vi.spyOn(sitemap, 'getModelPageCount').mockResolvedValue(2);
|
18
17
|
|
19
18
|
const index = await sitemap.getIndex();
|
@@ -31,7 +30,6 @@ describe('Sitemap', () => {
|
|
31
30
|
expect(index).toContain(`<loc>${getCanonicalUrl('/sitemap/assistants-1.xml')}</loc>`);
|
32
31
|
expect(index).toContain(`<loc>${getCanonicalUrl('/sitemap/assistants-2.xml')}</loc>`);
|
33
32
|
expect(index).toContain(`<loc>${getCanonicalUrl('/sitemap/assistants-3.xml')}</loc>`);
|
34
|
-
expect(index).toContain(`<loc>${getCanonicalUrl('/sitemap/mcp-1.xml')}</loc>`);
|
35
33
|
expect(index).toContain(`<loc>${getCanonicalUrl('/sitemap/models-1.xml')}</loc>`);
|
36
34
|
expect(index).toContain(`<loc>${getCanonicalUrl('/sitemap/models-2.xml')}</loc>`);
|
37
35
|
|
@@ -218,46 +216,6 @@ describe('Sitemap', () => {
|
|
218
216
|
});
|
219
217
|
});
|
220
218
|
|
221
|
-
describe('getMcp', () => {
|
222
|
-
it('should return a valid mcp sitemap without pagination', async () => {
|
223
|
-
vi.spyOn(sitemap['discoverService'], 'getMcpIdentifiers').mockResolvedValue([
|
224
|
-
// @ts-ignore
|
225
|
-
{ identifier: 'test-mcp', lastModified: '2023-01-01' },
|
226
|
-
]);
|
227
|
-
|
228
|
-
const mcpSitemap = await sitemap.getMcp();
|
229
|
-
expect(mcpSitemap.length).toBe(15);
|
230
|
-
expect(mcpSitemap).toContainEqual(
|
231
|
-
expect.objectContaining({
|
232
|
-
url: getCanonicalUrl('/discover/mcp/test-mcp'),
|
233
|
-
lastModified: '2023-01-01T00:00:00.000Z',
|
234
|
-
}),
|
235
|
-
);
|
236
|
-
expect(mcpSitemap).toContainEqual(
|
237
|
-
expect.objectContaining({
|
238
|
-
url: getCanonicalUrl('/discover/mcp/test-mcp?hl=zh-CN'),
|
239
|
-
lastModified: '2023-01-01T00:00:00.000Z',
|
240
|
-
}),
|
241
|
-
);
|
242
|
-
});
|
243
|
-
|
244
|
-
it('should return a valid mcp sitemap with pagination', async () => {
|
245
|
-
const mockMcps = Array.from({ length: 80 }, (_, i) => ({
|
246
|
-
identifier: `test-mcp-${i}`,
|
247
|
-
lastModified: '2023-01-01',
|
248
|
-
}));
|
249
|
-
|
250
|
-
vi.spyOn(sitemap['discoverService'], 'getMcpIdentifiers').mockResolvedValue(
|
251
|
-
// @ts-ignore
|
252
|
-
mockMcps,
|
253
|
-
);
|
254
|
-
|
255
|
-
// Test first page (should have 80 items, all on first page)
|
256
|
-
const firstPageSitemap = await sitemap.getMcp(1);
|
257
|
-
expect(firstPageSitemap.length).toBe(80 * 15); // 80 items * 15 locales
|
258
|
-
});
|
259
|
-
});
|
260
|
-
|
261
219
|
describe('getProviders', () => {
|
262
220
|
it('should return a valid providers sitemap', async () => {
|
263
221
|
vi.spyOn(sitemap['discoverService'], 'getProviderIdentifiers').mockResolvedValue([
|
@@ -303,16 +261,6 @@ describe('Sitemap', () => {
|
|
303
261
|
expect(pageCount).toBe(3); // 250 items / 100 per page = ceil(2.5) = 3 pages
|
304
262
|
});
|
305
263
|
|
306
|
-
it('should return correct mcp page count', async () => {
|
307
|
-
vi.spyOn(sitemap['discoverService'], 'getMcpIdentifiers').mockResolvedValue(
|
308
|
-
// @ts-ignore
|
309
|
-
Array.from({ length: 50 }, (_, i) => ({ identifier: `mcp-${i}` })),
|
310
|
-
);
|
311
|
-
|
312
|
-
const pageCount = await sitemap.getMcpPageCount();
|
313
|
-
expect(pageCount).toBe(1); // 50 items / 100 per page = 1 page
|
314
|
-
});
|
315
|
-
|
316
264
|
it('should return correct model page count', async () => {
|
317
265
|
vi.spyOn(sitemap['discoverService'], 'getModelIdentifiers').mockResolvedValue(
|
318
266
|
// @ts-ignore
|
package/src/server/sitemap.ts
CHANGED
@@ -52,12 +52,6 @@ export class Sitemap {
|
|
52
52
|
return Math.ceil(list.length / ITEMS_PER_PAGE);
|
53
53
|
}
|
54
54
|
|
55
|
-
// 获取MCP总页数
|
56
|
-
async getMcpPageCount(): Promise<number> {
|
57
|
-
const list = await this.discoverService.getMcpIdentifiers();
|
58
|
-
return Math.ceil(list.length / ITEMS_PER_PAGE);
|
59
|
-
}
|
60
|
-
|
61
55
|
// 获取模型总页数
|
62
56
|
async getModelPageCount(): Promise<number> {
|
63
57
|
const list = await this.discoverService.getModelIdentifiers();
|
@@ -171,10 +165,9 @@ export class Sitemap {
|
|
171
165
|
);
|
172
166
|
|
173
167
|
// 获取需要分页的类型的页数
|
174
|
-
const [pluginPages, assistantPages,
|
168
|
+
const [pluginPages, assistantPages, modelPages] = await Promise.all([
|
175
169
|
this.getPluginPageCount(),
|
176
170
|
this.getAssistantPageCount(),
|
177
|
-
this.getMcpPageCount(),
|
178
171
|
this.getModelPageCount(),
|
179
172
|
]);
|
180
173
|
|
@@ -193,11 +186,6 @@ export class Sitemap {
|
|
193
186
|
),
|
194
187
|
),
|
195
188
|
),
|
196
|
-
...Array.from({ length: mcpPages }, (_, i) =>
|
197
|
-
this._generateSitemapLink(
|
198
|
-
getCanonicalUrl(SITEMAP_BASE_URL, isDev ? `mcp-${i + 1}` : `mcp-${i + 1}.xml`),
|
199
|
-
),
|
200
|
-
),
|
201
189
|
...Array.from({ length: modelPages }, (_, i) =>
|
202
190
|
this._generateSitemapLink(
|
203
191
|
getCanonicalUrl(SITEMAP_BASE_URL, isDev ? `models-${i + 1}` : `models-${i + 1}.xml`),
|
@@ -239,31 +227,6 @@ export class Sitemap {
|
|
239
227
|
return flatten(sitmap);
|
240
228
|
}
|
241
229
|
|
242
|
-
async getMcp(page?: number): Promise<MetadataRoute.Sitemap> {
|
243
|
-
const list = await this.discoverService.getMcpIdentifiers();
|
244
|
-
|
245
|
-
if (page !== undefined) {
|
246
|
-
const startIndex = (page - 1) * ITEMS_PER_PAGE;
|
247
|
-
const endIndex = startIndex + ITEMS_PER_PAGE;
|
248
|
-
const pageMcps = list.slice(startIndex, endIndex);
|
249
|
-
|
250
|
-
const sitmap = pageMcps.map((item) =>
|
251
|
-
this._genSitemap(urlJoin('/discover/mcp', item.identifier), {
|
252
|
-
lastModified: item?.lastModified || LAST_MODIFIED,
|
253
|
-
}),
|
254
|
-
);
|
255
|
-
return flatten(sitmap);
|
256
|
-
}
|
257
|
-
|
258
|
-
// 如果没有指定页数,返回所有(向后兼容)
|
259
|
-
const sitmap = list.map((item) =>
|
260
|
-
this._genSitemap(urlJoin('/discover/mcp', item.identifier), {
|
261
|
-
lastModified: item?.lastModified || LAST_MODIFIED,
|
262
|
-
}),
|
263
|
-
);
|
264
|
-
return flatten(sitmap);
|
265
|
-
}
|
266
|
-
|
267
230
|
async getPlugins(page?: number): Promise<MetadataRoute.Sitemap> {
|
268
231
|
const list = await this.discoverService.getPluginIdentifiers();
|
269
232
|
|
package/src/services/_auth.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { ClientSecretPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
|
2
2
|
import { isDeprecatedEdition } from '@/const/version';
|
3
3
|
import { ModelProvider } from '@/libs/model-runtime';
|
4
4
|
import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
|
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
CloudflareKeyVault,
|
11
11
|
OpenAICompatibleKeyVault,
|
12
12
|
} from '@/types/user/settings';
|
13
|
-
import {
|
13
|
+
import { obfuscatePayloadWithXOR } from '@/utils/client/xor-obfuscation';
|
14
14
|
|
15
15
|
export const getProviderAuthPayload = (
|
16
16
|
provider: string,
|
@@ -80,7 +80,7 @@ const createAuthTokenWithPayload = async (payload = {}) => {
|
|
80
80
|
const accessCode = keyVaultsConfigSelectors.password(useUserStore.getState());
|
81
81
|
const userId = userProfileSelectors.userId(useUserStore.getState());
|
82
82
|
|
83
|
-
return
|
83
|
+
return obfuscatePayloadWithXOR<ClientSecretPayload>({ accessCode, userId, ...payload });
|
84
84
|
};
|
85
85
|
|
86
86
|
interface AuthParams {
|
package/src/services/discover.ts
CHANGED
@@ -83,10 +83,6 @@ class DiscoverService {
|
|
83
83
|
});
|
84
84
|
};
|
85
85
|
|
86
|
-
getMcpIdentifiers = async (): Promise<IdentifiersResponse> => {
|
87
|
-
return lambdaClient.market.getMcpIdentifiers.query();
|
88
|
-
};
|
89
|
-
|
90
86
|
getMcpList = async (params: McpQueryParams = {}): Promise<McpListResponse> => {
|
91
87
|
const locale = globalHelpers.getCurrentLanguage();
|
92
88
|
return lambdaClient.market.getMcpList.query({
|
@@ -8,7 +8,6 @@ import { DiscoverStore } from '@/store/discover';
|
|
8
8
|
import { globalHelpers } from '@/store/global/helpers';
|
9
9
|
import {
|
10
10
|
DiscoverMcpDetail,
|
11
|
-
IdentifiersResponse,
|
12
11
|
McpListResponse,
|
13
12
|
McpQueryParams,
|
14
13
|
} from '@/types/discover';
|
@@ -20,7 +19,6 @@ export interface MCPAction {
|
|
20
19
|
}) => SWRResponse<DiscoverMcpDetail>;
|
21
20
|
useFetchMcpList: (params: McpQueryParams) => SWRResponse<McpListResponse>;
|
22
21
|
useMcpCategories: (params: CategoryListQuery) => SWRResponse<CategoryItem[]>;
|
23
|
-
useMcpIdentifiers: () => SWRResponse<IdentifiersResponse>;
|
24
22
|
}
|
25
23
|
|
26
24
|
export const createMCPSlice: StateCreator<
|
@@ -61,10 +59,4 @@ export const createMCPSlice: StateCreator<
|
|
61
59
|
},
|
62
60
|
);
|
63
61
|
},
|
64
|
-
|
65
|
-
useMcpIdentifiers: () => {
|
66
|
-
return useClientDataSWR('mcp-identifiers', async () => discoverService.getMcpIdentifiers(), {
|
67
|
-
revalidateOnFocus: false,
|
68
|
-
});
|
69
|
-
},
|
70
62
|
});
|