@lobehub/chat 1.77.5 → 1.77.7
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/scripts/pr-comment.js +80 -0
- package/.github/scripts/pr-release-body.js +59 -0
- package/.github/workflows/release-desktop.yml +331 -0
- package/.github/workflows/test.yml +1 -1
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/next.config.ts +16 -11
- package/package.json +92 -89
- package/packages/electron-client-ipc/README.md +48 -0
- package/packages/electron-client-ipc/package.json +7 -0
- package/packages/electron-client-ipc/src/events/devtools.ts +6 -0
- package/packages/electron-client-ipc/src/events/index.ts +13 -0
- package/packages/electron-client-ipc/src/index.ts +2 -0
- package/packages/electron-client-ipc/src/types/dispatch.ts +10 -0
- package/packages/electron-client-ipc/src/types/index.ts +1 -0
- package/packages/electron-server-ipc/README.md +1 -1
- package/pnpm-workspace.yaml +1 -0
- package/scripts/setup-test-postgres-db.sh +21 -0
- package/src/app/desktop/devtools/page.tsx +89 -0
- package/src/app/desktop/layout.tsx +31 -0
- package/src/app/layout.tsx +11 -0
- package/src/app/not-found.tsx +1 -0
- package/src/const/desktop.ts +1 -0
- package/src/const/version.ts +2 -0
- package/src/database/client/db.ts +3 -10
- package/src/database/core/db-adaptor.ts +20 -2
- package/src/database/models/__tests__/aiProvider.test.ts +2 -0
- package/src/database/models/__tests__/message.test.ts +97 -26
- package/src/database/models/__tests__/session.test.ts +2 -0
- package/src/database/models/drizzleMigration.ts +15 -0
- package/src/database/models/message.ts +10 -5
- package/src/database/models/session.ts +8 -0
- package/src/database/models/user.ts +10 -1
- package/src/database/server/index.ts +1 -1
- package/src/features/DevPanel/features/FloatPanel.tsx +23 -6
- package/src/features/User/UserPanel/index.tsx +10 -6
- package/src/libs/trpc/async/index.ts +11 -1
- package/src/libs/trpc/lambda/index.ts +1 -0
- package/src/libs/trpc/lambda/serverDatabase.ts +10 -0
- package/src/libs/trpc/middleware/userAuth.ts +10 -0
- package/src/server/routers/async/file.ts +4 -5
- package/src/server/routers/async/ragEval.ts +3 -4
- package/src/server/routers/lambda/_template.ts +3 -5
- package/src/server/routers/lambda/agent.ts +8 -8
- package/src/server/routers/lambda/aiModel.ts +5 -5
- package/src/server/routers/lambda/aiProvider.test.ts +0 -2
- package/src/server/routers/lambda/aiProvider.ts +5 -5
- package/src/server/routers/lambda/chunk.ts +18 -15
- package/src/server/routers/lambda/exporter.ts +4 -4
- package/src/server/routers/lambda/file.ts +5 -5
- package/src/server/routers/lambda/importer.ts +3 -3
- package/src/server/routers/lambda/knowledgeBase.ts +3 -3
- package/src/server/routers/lambda/message.ts +5 -3
- package/src/server/routers/lambda/plugin.ts +5 -3
- package/src/server/routers/lambda/ragEval.ts +17 -14
- package/src/server/routers/lambda/session.ts +6 -4
- package/src/server/routers/lambda/sessionGroup.ts +3 -3
- package/src/server/routers/lambda/thread.ts +4 -4
- package/src/server/routers/lambda/topic.ts +5 -3
- package/src/server/routers/lambda/user.ts +7 -7
- package/src/server/routers/tools/__tests__/search.test.ts +1 -0
- package/src/server/services/nextAuthUser/index.test.ts +1 -2
- package/src/server/translation.test.ts +72 -52
- package/src/server/translation.ts +2 -11
- package/src/services/electron/devtools.ts +9 -0
- package/src/styles/electron.ts +14 -0
- package/src/tools/web-browsing/Portal/Search/ResultList/SearchItem/index.tsx +3 -8
- package/src/tools/web-browsing/Render/Search/SearchResult/ShowMore.tsx +2 -4
- package/src/types/electron.ts +11 -0
- package/src/utils/electron/dispatch.ts +10 -0
- package/tsconfig.json +6 -6
- package/vitest.config.ts +3 -1
- package/vitest.server.config.ts +7 -3
@@ -3,8 +3,8 @@ import { z } from 'zod';
|
|
3
3
|
import { AiProviderModel } from '@/database/models/aiProvider';
|
4
4
|
import { UserModel } from '@/database/models/user';
|
5
5
|
import { AiInfraRepos } from '@/database/repositories/aiInfra';
|
6
|
-
import { serverDB } from '@/database/server';
|
7
6
|
import { authedProcedure, router } from '@/libs/trpc';
|
7
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
8
8
|
import { getServerGlobalConfig } from '@/server/globalConfig';
|
9
9
|
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
10
10
|
import {
|
@@ -16,7 +16,7 @@ import {
|
|
16
16
|
} from '@/types/aiProvider';
|
17
17
|
import { ProviderConfig } from '@/types/user/settings';
|
18
18
|
|
19
|
-
const aiProviderProcedure = authedProcedure.use(async (opts) => {
|
19
|
+
const aiProviderProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
20
20
|
const { ctx } = opts;
|
21
21
|
|
22
22
|
const { aiProvider } = await getServerGlobalConfig();
|
@@ -25,13 +25,13 @@ const aiProviderProcedure = authedProcedure.use(async (opts) => {
|
|
25
25
|
return opts.next({
|
26
26
|
ctx: {
|
27
27
|
aiInfraRepos: new AiInfraRepos(
|
28
|
-
serverDB,
|
28
|
+
ctx.serverDB,
|
29
29
|
ctx.userId,
|
30
30
|
aiProvider as Record<string, ProviderConfig>,
|
31
31
|
),
|
32
|
-
aiProviderModel: new AiProviderModel(serverDB, ctx.userId),
|
32
|
+
aiProviderModel: new AiProviderModel(ctx.serverDB, ctx.userId),
|
33
33
|
gateKeeper,
|
34
|
-
userModel: new UserModel(serverDB, ctx.userId),
|
34
|
+
userModel: new UserModel(ctx.serverDB, ctx.userId),
|
35
35
|
},
|
36
36
|
});
|
37
37
|
});
|
@@ -9,28 +9,31 @@ import { EmbeddingModel } from '@/database/models/embedding';
|
|
9
9
|
import { FileModel } from '@/database/models/file';
|
10
10
|
import { MessageModel } from '@/database/models/message';
|
11
11
|
import { knowledgeBaseFiles } from '@/database/schemas';
|
12
|
-
import { serverDB } from '@/database/server';
|
13
12
|
import { authedProcedure, router } from '@/libs/trpc';
|
13
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
14
14
|
import { keyVaults } from '@/libs/trpc/middleware/keyVaults';
|
15
15
|
import { getServerDefaultFilesConfig } from '@/server/globalConfig';
|
16
16
|
import { initAgentRuntimeWithUserPayload } from '@/server/modules/AgentRuntime';
|
17
17
|
import { ChunkService } from '@/server/services/chunk';
|
18
18
|
import { SemanticSearchSchema } from '@/types/rag';
|
19
19
|
|
20
|
-
const chunkProcedure = authedProcedure
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
ctx
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
const chunkProcedure = authedProcedure
|
21
|
+
.use(serverDatabase)
|
22
|
+
.use(keyVaults)
|
23
|
+
.use(async (opts) => {
|
24
|
+
const { ctx } = opts;
|
25
|
+
|
26
|
+
return opts.next({
|
27
|
+
ctx: {
|
28
|
+
asyncTaskModel: new AsyncTaskModel(ctx.serverDB, ctx.userId),
|
29
|
+
chunkModel: new ChunkModel(ctx.serverDB, ctx.userId),
|
30
|
+
chunkService: new ChunkService(ctx.userId),
|
31
|
+
embeddingModel: new EmbeddingModel(ctx.serverDB, ctx.userId),
|
32
|
+
fileModel: new FileModel(ctx.serverDB, ctx.userId),
|
33
|
+
messageModel: new MessageModel(ctx.serverDB, ctx.userId),
|
34
|
+
},
|
35
|
+
});
|
32
36
|
});
|
33
|
-
});
|
34
37
|
|
35
38
|
export const chunkRouter = router({
|
36
39
|
createEmbeddingChunksTask: chunkProcedure
|
@@ -173,7 +176,7 @@ export const chunkRouter = router({
|
|
173
176
|
let finalFileIds = input.fileIds ?? [];
|
174
177
|
|
175
178
|
if (input.knowledgeIds && input.knowledgeIds.length > 0) {
|
176
|
-
const knowledgeFiles = await serverDB.query.knowledgeBaseFiles.findMany({
|
179
|
+
const knowledgeFiles = await ctx.serverDB.query.knowledgeBaseFiles.findMany({
|
177
180
|
where: inArray(knowledgeBaseFiles.knowledgeBaseId, input.knowledgeIds),
|
178
181
|
});
|
179
182
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import { DrizzleMigrationModel } from '@/database/models/drizzleMigration';
|
2
2
|
import { DataExporterRepos } from '@/database/repositories/dataExporter';
|
3
|
-
import { serverDB } from '@/database/server';
|
4
3
|
import { authedProcedure, router } from '@/libs/trpc';
|
4
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
5
5
|
import { ExportDatabaseData } from '@/types/export';
|
6
6
|
|
7
|
-
const exportProcedure = authedProcedure.use(async (opts) => {
|
7
|
+
const exportProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
8
8
|
const { ctx } = opts;
|
9
|
-
const dataExporterRepos = new DataExporterRepos(serverDB, ctx.userId);
|
10
|
-
const drizzleMigration = new DrizzleMigrationModel(serverDB);
|
9
|
+
const dataExporterRepos = new DataExporterRepos(ctx.serverDB, ctx.userId);
|
10
|
+
const drizzleMigration = new DrizzleMigrationModel(ctx.serverDB);
|
11
11
|
|
12
12
|
return opts.next({
|
13
13
|
ctx: { dataExporterRepos, drizzleMigration },
|
@@ -5,21 +5,21 @@ import { serverDBEnv } from '@/config/db';
|
|
5
5
|
import { AsyncTaskModel } from '@/database/models/asyncTask';
|
6
6
|
import { ChunkModel } from '@/database/models/chunk';
|
7
7
|
import { FileModel } from '@/database/models/file';
|
8
|
-
import { serverDB } from '@/database/server';
|
9
8
|
import { authedProcedure, router } from '@/libs/trpc';
|
9
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
10
10
|
import { S3 } from '@/server/modules/S3';
|
11
11
|
import { getFullFileUrl } from '@/server/utils/files';
|
12
12
|
import { AsyncTaskStatus, AsyncTaskType } from '@/types/asyncTask';
|
13
13
|
import { FileListItem, QueryFileListSchema, UploadFileSchema } from '@/types/files';
|
14
14
|
|
15
|
-
const fileProcedure = authedProcedure.use(async (opts) => {
|
15
|
+
const fileProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
16
16
|
const { ctx } = opts;
|
17
17
|
|
18
18
|
return opts.next({
|
19
19
|
ctx: {
|
20
|
-
asyncTaskModel: new AsyncTaskModel(serverDB, ctx.userId),
|
21
|
-
chunkModel: new ChunkModel(serverDB, ctx.userId),
|
22
|
-
fileModel: new FileModel(serverDB, ctx.userId),
|
20
|
+
asyncTaskModel: new AsyncTaskModel(ctx.serverDB, ctx.userId),
|
21
|
+
chunkModel: new ChunkModel(ctx.serverDB, ctx.userId),
|
22
|
+
fileModel: new FileModel(ctx.serverDB, ctx.userId),
|
23
23
|
},
|
24
24
|
});
|
25
25
|
});
|
@@ -2,15 +2,15 @@ import { TRPCError } from '@trpc/server';
|
|
2
2
|
import { z } from 'zod';
|
3
3
|
|
4
4
|
import { DataImporterRepos } from '@/database/repositories/dataImporter';
|
5
|
-
import { serverDB } from '@/database/server';
|
6
5
|
import { authedProcedure, router } from '@/libs/trpc';
|
6
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
7
7
|
import { S3 } from '@/server/modules/S3';
|
8
8
|
import { ImportPgDataStructure } from '@/types/export';
|
9
9
|
import { ImportResultData, ImporterEntryData } from '@/types/importer';
|
10
10
|
|
11
|
-
const importProcedure = authedProcedure.use(async (opts) => {
|
11
|
+
const importProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
12
12
|
const { ctx } = opts;
|
13
|
-
const dataImporterService = new DataImporterRepos(serverDB, ctx.userId);
|
13
|
+
const dataImporterService = new DataImporterRepos(ctx.serverDB, ctx.userId);
|
14
14
|
|
15
15
|
return opts.next({
|
16
16
|
ctx: { dataImporterService },
|
@@ -2,16 +2,16 @@ import { z } from 'zod';
|
|
2
2
|
|
3
3
|
import { KnowledgeBaseModel } from '@/database/models/knowledgeBase';
|
4
4
|
import { insertKnowledgeBasesSchema } from '@/database/schemas';
|
5
|
-
import { serverDB } from '@/database/server';
|
6
5
|
import { authedProcedure, router } from '@/libs/trpc';
|
6
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
7
7
|
import { KnowledgeBaseItem } from '@/types/knowledgeBase';
|
8
8
|
|
9
|
-
const knowledgeBaseProcedure = authedProcedure.use(async (opts) => {
|
9
|
+
const knowledgeBaseProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
10
10
|
const { ctx } = opts;
|
11
11
|
|
12
12
|
return opts.next({
|
13
13
|
ctx: {
|
14
|
-
knowledgeBaseModel: new KnowledgeBaseModel(serverDB, ctx.userId),
|
14
|
+
knowledgeBaseModel: new KnowledgeBaseModel(ctx.serverDB, ctx.userId),
|
15
15
|
},
|
16
16
|
});
|
17
17
|
});
|
@@ -2,19 +2,20 @@ import { z } from 'zod';
|
|
2
2
|
|
3
3
|
import { MessageModel } from '@/database/models/message';
|
4
4
|
import { updateMessagePluginSchema } from '@/database/schemas';
|
5
|
-
import {
|
5
|
+
import { getServerDB } from '@/database/server';
|
6
6
|
import { authedProcedure, publicProcedure, router } from '@/libs/trpc';
|
7
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
7
8
|
import { getFullFileUrl } from '@/server/utils/files';
|
8
9
|
import { ChatMessage } from '@/types/message';
|
9
10
|
import { BatchTaskResult } from '@/types/service';
|
10
11
|
|
11
12
|
type ChatMessageList = ChatMessage[];
|
12
13
|
|
13
|
-
const messageProcedure = authedProcedure.use(async (opts) => {
|
14
|
+
const messageProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
14
15
|
const { ctx } = opts;
|
15
16
|
|
16
17
|
return opts.next({
|
17
|
-
ctx: { messageModel: new MessageModel(serverDB, ctx.userId) },
|
18
|
+
ctx: { messageModel: new MessageModel(ctx.serverDB, ctx.userId) },
|
18
19
|
});
|
19
20
|
});
|
20
21
|
|
@@ -95,6 +96,7 @@ export const messageRouter = router({
|
|
95
96
|
)
|
96
97
|
.query(async ({ input, ctx }) => {
|
97
98
|
if (!ctx.userId) return [];
|
99
|
+
const serverDB = await getServerDB();
|
98
100
|
|
99
101
|
const messageModel = new MessageModel(serverDB, ctx.userId);
|
100
102
|
|
@@ -1,15 +1,16 @@
|
|
1
1
|
import { z } from 'zod';
|
2
2
|
|
3
3
|
import { PluginModel } from '@/database/models/plugin';
|
4
|
-
import {
|
4
|
+
import { getServerDB } from '@/database/server';
|
5
5
|
import { authedProcedure, publicProcedure, router } from '@/libs/trpc';
|
6
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
6
7
|
import { LobeTool } from '@/types/tool';
|
7
8
|
|
8
|
-
const pluginProcedure = authedProcedure.use(async (opts) => {
|
9
|
+
const pluginProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
9
10
|
const { ctx } = opts;
|
10
11
|
|
11
12
|
return opts.next({
|
12
|
-
ctx: { pluginModel: new PluginModel(serverDB, ctx.userId) },
|
13
|
+
ctx: { pluginModel: new PluginModel(ctx.serverDB, ctx.userId) },
|
13
14
|
});
|
14
15
|
});
|
15
16
|
|
@@ -66,6 +67,7 @@ export const pluginRouter = router({
|
|
66
67
|
getPlugins: publicProcedure.query(async ({ ctx }): Promise<LobeTool[]> => {
|
67
68
|
if (!ctx.userId) return [];
|
68
69
|
|
70
|
+
const serverDB = await getServerDB();
|
69
71
|
const pluginModel = new PluginModel(serverDB, ctx.userId);
|
70
72
|
|
71
73
|
return pluginModel.query();
|
@@ -7,7 +7,6 @@ import { z } from 'zod';
|
|
7
7
|
|
8
8
|
import { DEFAULT_EMBEDDING_MODEL, DEFAULT_MODEL } from '@/const/settings';
|
9
9
|
import { FileModel } from '@/database/models/file';
|
10
|
-
import { serverDB } from '@/database/server';
|
11
10
|
import {
|
12
11
|
EvalDatasetModel,
|
13
12
|
EvalDatasetRecordModel,
|
@@ -15,6 +14,7 @@ import {
|
|
15
14
|
EvaluationRecordModel,
|
16
15
|
} from '@/database/server/models/ragEval';
|
17
16
|
import { authedProcedure, router } from '@/libs/trpc';
|
17
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
18
18
|
import { keyVaults } from '@/libs/trpc/middleware/keyVaults';
|
19
19
|
import { S3 } from '@/server/modules/S3';
|
20
20
|
import { createAsyncServerClient } from '@/server/routers/async';
|
@@ -29,20 +29,23 @@ import {
|
|
29
29
|
insertEvalEvaluationSchema,
|
30
30
|
} from '@/types/eval';
|
31
31
|
|
32
|
-
const ragEvalProcedure = authedProcedure
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
ctx
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
32
|
+
const ragEvalProcedure = authedProcedure
|
33
|
+
.use(serverDatabase)
|
34
|
+
.use(keyVaults)
|
35
|
+
.use(async (opts) => {
|
36
|
+
const { ctx } = opts;
|
37
|
+
|
38
|
+
return opts.next({
|
39
|
+
ctx: {
|
40
|
+
datasetModel: new EvalDatasetModel(ctx.userId),
|
41
|
+
fileModel: new FileModel(ctx.serverDB, ctx.userId),
|
42
|
+
datasetRecordModel: new EvalDatasetRecordModel(ctx.userId),
|
43
|
+
evaluationModel: new EvalEvaluationModel(ctx.userId),
|
44
|
+
evaluationRecordModel: new EvaluationRecordModel(ctx.userId),
|
45
|
+
s3: new S3(),
|
46
|
+
},
|
47
|
+
});
|
44
48
|
});
|
45
|
-
});
|
46
49
|
|
47
50
|
export const ragEvalRouter = router({
|
48
51
|
createDataset: ragEvalProcedure
|
@@ -3,21 +3,22 @@ import { z } from 'zod';
|
|
3
3
|
import { SessionModel } from '@/database/models/session';
|
4
4
|
import { SessionGroupModel } from '@/database/models/sessionGroup';
|
5
5
|
import { insertAgentSchema, insertSessionSchema } from '@/database/schemas';
|
6
|
-
import {
|
6
|
+
import { getServerDB } from '@/database/server';
|
7
7
|
import { authedProcedure, publicProcedure, router } from '@/libs/trpc';
|
8
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
8
9
|
import { AgentChatConfigSchema } from '@/types/agent';
|
9
10
|
import { LobeMetaDataSchema } from '@/types/meta';
|
10
11
|
import { BatchTaskResult } from '@/types/service';
|
11
12
|
import { ChatSessionList } from '@/types/session';
|
12
13
|
import { merge } from '@/utils/merge';
|
13
14
|
|
14
|
-
const sessionProcedure = authedProcedure.use(async (opts) => {
|
15
|
+
const sessionProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
15
16
|
const { ctx } = opts;
|
16
17
|
|
17
18
|
return opts.next({
|
18
19
|
ctx: {
|
19
|
-
sessionGroupModel: new SessionGroupModel(serverDB, ctx.userId),
|
20
|
-
sessionModel: new SessionModel(serverDB, ctx.userId),
|
20
|
+
sessionGroupModel: new SessionGroupModel(ctx.serverDB, ctx.userId),
|
21
|
+
sessionModel: new SessionModel(ctx.serverDB, ctx.userId),
|
21
22
|
},
|
22
23
|
});
|
23
24
|
});
|
@@ -95,6 +96,7 @@ export const sessionRouter = router({
|
|
95
96
|
sessions: [],
|
96
97
|
};
|
97
98
|
|
99
|
+
const serverDB = await getServerDB();
|
98
100
|
const sessionModel = new SessionModel(serverDB, ctx.userId);
|
99
101
|
|
100
102
|
return sessionModel.queryWithGroups();
|
@@ -2,16 +2,16 @@ import { z } from 'zod';
|
|
2
2
|
|
3
3
|
import { SessionGroupModel } from '@/database/models/sessionGroup';
|
4
4
|
import { insertSessionGroupSchema } from '@/database/schemas';
|
5
|
-
import { serverDB } from '@/database/server';
|
6
5
|
import { authedProcedure, router } from '@/libs/trpc';
|
6
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
7
7
|
import { SessionGroupItem } from '@/types/session';
|
8
8
|
|
9
|
-
const sessionProcedure = authedProcedure.use(async (opts) => {
|
9
|
+
const sessionProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
10
10
|
const { ctx } = opts;
|
11
11
|
|
12
12
|
return opts.next({
|
13
13
|
ctx: {
|
14
|
-
sessionGroupModel: new SessionGroupModel(serverDB, ctx.userId),
|
14
|
+
sessionGroupModel: new SessionGroupModel(ctx.serverDB, ctx.userId),
|
15
15
|
},
|
16
16
|
});
|
17
17
|
});
|
@@ -3,17 +3,17 @@ import { z } from 'zod';
|
|
3
3
|
import { MessageModel } from '@/database/models/message';
|
4
4
|
import { ThreadModel } from '@/database/models/thread';
|
5
5
|
import { insertThreadSchema } from '@/database/schemas';
|
6
|
-
import { serverDB } from '@/database/server';
|
7
6
|
import { authedProcedure, router } from '@/libs/trpc';
|
7
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
8
8
|
import { ThreadItem, createThreadSchema } from '@/types/topic/thread';
|
9
9
|
|
10
|
-
const threadProcedure = authedProcedure.use(async (opts) => {
|
10
|
+
const threadProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
11
11
|
const { ctx } = opts;
|
12
12
|
|
13
13
|
return opts.next({
|
14
14
|
ctx: {
|
15
|
-
messageModel: new MessageModel(serverDB, ctx.userId),
|
16
|
-
threadModel: new ThreadModel(serverDB, ctx.userId),
|
15
|
+
messageModel: new MessageModel(ctx.serverDB, ctx.userId),
|
16
|
+
threadModel: new ThreadModel(ctx.serverDB, ctx.userId),
|
17
17
|
},
|
18
18
|
});
|
19
19
|
});
|
@@ -1,15 +1,16 @@
|
|
1
1
|
import { z } from 'zod';
|
2
2
|
|
3
3
|
import { TopicModel } from '@/database/models/topic';
|
4
|
-
import {
|
4
|
+
import { getServerDB } from '@/database/server';
|
5
5
|
import { authedProcedure, publicProcedure, router } from '@/libs/trpc';
|
6
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
6
7
|
import { BatchTaskResult } from '@/types/service';
|
7
8
|
|
8
|
-
const topicProcedure = authedProcedure.use(async (opts) => {
|
9
|
+
const topicProcedure = authedProcedure.use(serverDatabase).use(async (opts) => {
|
9
10
|
const { ctx } = opts;
|
10
11
|
|
11
12
|
return opts.next({
|
12
|
-
ctx: { topicModel: new TopicModel(serverDB, ctx.userId) },
|
13
|
+
ctx: { topicModel: new TopicModel(ctx.serverDB, ctx.userId) },
|
13
14
|
});
|
14
15
|
});
|
15
16
|
|
@@ -101,6 +102,7 @@ export const topicRouter = router({
|
|
101
102
|
.query(async ({ input, ctx }) => {
|
102
103
|
if (!ctx.userId) return [];
|
103
104
|
|
105
|
+
const serverDB = await getServerDB();
|
104
106
|
const topicModel = new TopicModel(serverDB, ctx.userId);
|
105
107
|
|
106
108
|
return topicModel.query(input);
|
@@ -5,10 +5,10 @@ import { enableClerk } from '@/const/auth';
|
|
5
5
|
import { MessageModel } from '@/database/models/message';
|
6
6
|
import { SessionModel } from '@/database/models/session';
|
7
7
|
import { UserModel, UserNotFoundError } from '@/database/models/user';
|
8
|
-
import { serverDB } from '@/database/server';
|
9
8
|
import { ClerkAuth } from '@/libs/clerk-auth';
|
10
9
|
import { LobeNextAuthDbAdapter } from '@/libs/next-auth/adapter';
|
11
10
|
import { authedProcedure, router } from '@/libs/trpc';
|
11
|
+
import { serverDatabase } from '@/libs/trpc/lambda';
|
12
12
|
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
13
13
|
import { UserService } from '@/server/services/user';
|
14
14
|
import {
|
@@ -19,12 +19,12 @@ import {
|
|
19
19
|
} from '@/types/user';
|
20
20
|
import { UserSettings } from '@/types/user/settings';
|
21
21
|
|
22
|
-
const userProcedure = authedProcedure.use(async (
|
23
|
-
return
|
22
|
+
const userProcedure = authedProcedure.use(serverDatabase).use(async ({ ctx, next }) => {
|
23
|
+
return next({
|
24
24
|
ctx: {
|
25
25
|
clerkAuth: new ClerkAuth(),
|
26
|
-
nextAuthDbAdapter: LobeNextAuthDbAdapter(serverDB),
|
27
|
-
userModel: new UserModel(serverDB,
|
26
|
+
nextAuthDbAdapter: LobeNextAuthDbAdapter(ctx.serverDB),
|
27
|
+
userModel: new UserModel(ctx.serverDB, ctx.userId),
|
28
28
|
},
|
29
29
|
});
|
30
30
|
});
|
@@ -77,10 +77,10 @@ export const userRouter = router({
|
|
77
77
|
}
|
78
78
|
}
|
79
79
|
|
80
|
-
const messageModel = new MessageModel(serverDB, ctx.userId);
|
80
|
+
const messageModel = new MessageModel(ctx.serverDB, ctx.userId);
|
81
81
|
const hasMoreThan4Messages = await messageModel.hasMoreThanN(4);
|
82
82
|
|
83
|
-
const sessionModel = new SessionModel(serverDB, ctx.userId);
|
83
|
+
const sessionModel = new SessionModel(ctx.serverDB, ctx.userId);
|
84
84
|
const hasAnyMessages = await messageModel.hasMoreThanN(0);
|
85
85
|
const hasExtraSession = await sessionModel.hasMoreThanN(1);
|
86
86
|
|
@@ -6,7 +6,6 @@ import { UserModel } from '@/database/models/user';
|
|
6
6
|
import { UserItem } from '@/database/schemas';
|
7
7
|
import { serverDB } from '@/database/server';
|
8
8
|
import { pino } from '@/libs/logger';
|
9
|
-
import { LobeNextAuthDbAdapter } from '@/libs/next-auth/adapter';
|
10
9
|
|
11
10
|
import { NextAuthUserService } from './index';
|
12
11
|
|
@@ -23,7 +22,7 @@ vi.mock('@/database/server');
|
|
23
22
|
describe('NextAuthUserService', () => {
|
24
23
|
let service: NextAuthUserService;
|
25
24
|
|
26
|
-
beforeEach(() => {
|
25
|
+
beforeEach(async () => {
|
27
26
|
vi.clearAllMocks();
|
28
27
|
service = new NextAuthUserService();
|
29
28
|
});
|
@@ -1,12 +1,9 @@
|
|
1
1
|
// @vitest-environment node
|
2
2
|
import { cookies } from 'next/headers';
|
3
|
-
import
|
4
|
-
import * as path from 'node:path';
|
5
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
6
4
|
|
7
|
-
import { DEFAULT_LANG
|
5
|
+
import { DEFAULT_LANG } from '@/const/locale';
|
8
6
|
import { normalizeLocale } from '@/locales/resources';
|
9
|
-
import * as env from '@/utils/env';
|
10
7
|
|
11
8
|
import { getLocale, translation } from './translation';
|
12
9
|
|
@@ -15,15 +12,6 @@ vi.mock('next/headers', () => ({
|
|
15
12
|
cookies: vi.fn(),
|
16
13
|
}));
|
17
14
|
|
18
|
-
vi.mock('node:fs', () => ({
|
19
|
-
existsSync: vi.fn(),
|
20
|
-
readFileSync: vi.fn(),
|
21
|
-
}));
|
22
|
-
|
23
|
-
vi.mock('node:path', () => ({
|
24
|
-
join: vi.fn(),
|
25
|
-
}));
|
26
|
-
|
27
15
|
vi.mock('@/const/locale', () => ({
|
28
16
|
DEFAULT_LANG: 'en-US',
|
29
17
|
LOBE_LOCALE_COOKIE: 'LOBE_LOCALE',
|
@@ -37,6 +25,28 @@ vi.mock('@/utils/env', () => ({
|
|
37
25
|
isDev: false,
|
38
26
|
}));
|
39
27
|
|
28
|
+
// 模拟动态导入结果
|
29
|
+
const mockTranslations = {
|
30
|
+
key1: 'Value 1',
|
31
|
+
key2: 'Value 2 with {{param}}',
|
32
|
+
nested: { key: 'Nested value' },
|
33
|
+
};
|
34
|
+
|
35
|
+
const mockDefaultTranslations = {
|
36
|
+
key1: '默认值 1',
|
37
|
+
key2: '默认值 2 带 {{param}}',
|
38
|
+
nested: { key: '默认嵌套值' },
|
39
|
+
};
|
40
|
+
|
41
|
+
// 重写导入函数
|
42
|
+
vi.mock('@/../locales/en-US/common.json', async () => {
|
43
|
+
return mockTranslations;
|
44
|
+
});
|
45
|
+
|
46
|
+
vi.mock('@/locales/default/common', async () => {
|
47
|
+
return mockDefaultTranslations;
|
48
|
+
});
|
49
|
+
|
40
50
|
describe('getLocale', () => {
|
41
51
|
const mockCookieStore = {
|
42
52
|
get: vi.fn(),
|
@@ -61,17 +71,12 @@ describe('getLocale', () => {
|
|
61
71
|
});
|
62
72
|
|
63
73
|
describe('translation', () => {
|
64
|
-
const mockTranslations = {
|
65
|
-
key1: 'Value 1',
|
66
|
-
key2: 'Value 2 with {{param}}',
|
67
|
-
nested: { key: 'Nested value' },
|
68
|
-
};
|
69
|
-
|
70
74
|
beforeEach(() => {
|
71
75
|
vi.clearAllMocks();
|
72
|
-
|
73
|
-
(
|
74
|
-
|
76
|
+
// 重置 import 模拟
|
77
|
+
vi.doMock('@/../locales/en-US/common.json', async () => {
|
78
|
+
return mockTranslations;
|
79
|
+
});
|
75
80
|
});
|
76
81
|
|
77
82
|
it('should return correct translation object', async () => {
|
@@ -88,43 +93,58 @@ describe('translation', () => {
|
|
88
93
|
expect(t('nested.key')).toBe('Nested value');
|
89
94
|
});
|
90
95
|
|
91
|
-
it('should
|
96
|
+
it('should handle multiple parameters in translation string', async () => {
|
97
|
+
// 模拟多参数翻译
|
98
|
+
vi.doMock('@/../locales/en-US/common.json', async () => ({
|
99
|
+
multiParam: 'Hello {{name}}, you have {{count}} messages',
|
100
|
+
}));
|
101
|
+
|
92
102
|
const { t } = await translation('common', 'en-US');
|
93
|
-
expect(t('
|
103
|
+
expect(t('multiParam', { name: 'John', count: '5' })).toBe('Hello John, you have 5 messages');
|
94
104
|
});
|
95
105
|
|
96
|
-
it('should
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
);
|
106
|
+
it('should handle different namespaces', async () => {
|
107
|
+
// 模拟另一个命名空间
|
108
|
+
vi.doMock('@/../locales/en-US/chat.json', async () => ({
|
109
|
+
welcome: 'Welcome to the chat',
|
110
|
+
}));
|
111
|
+
|
112
|
+
const { t } = await translation('chat', 'en-US');
|
113
|
+
expect(t('welcome')).toBe('Welcome to the chat');
|
103
114
|
});
|
104
115
|
|
105
|
-
it('should
|
106
|
-
|
107
|
-
(
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
116
|
+
it('should handle deep nested objects in translations', async () => {
|
117
|
+
// 模拟深层嵌套对象
|
118
|
+
vi.doMock('@/../locales/en-US/common.json', async () => ({
|
119
|
+
very: {
|
120
|
+
deeply: {
|
121
|
+
nested: {
|
122
|
+
key: 'Found the nested value',
|
123
|
+
},
|
124
|
+
},
|
125
|
+
},
|
126
|
+
}));
|
127
|
+
|
128
|
+
const { t } = await translation('common', 'en-US');
|
129
|
+
expect(t('very.deeply.nested.key')).toBe('Found the nested value');
|
113
130
|
});
|
114
131
|
|
115
|
-
it('should handle
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
});
|
132
|
+
it('should handle empty parameters object', async () => {
|
133
|
+
vi.doMock('@/../locales/en-US/common.json', async () => ({
|
134
|
+
simpleText: 'Just a simple text',
|
135
|
+
}));
|
120
136
|
|
121
|
-
const
|
122
|
-
expect(
|
123
|
-
|
124
|
-
'Error while reading translation file',
|
125
|
-
expect.any(Error),
|
126
|
-
);
|
137
|
+
const { t } = await translation('common', 'en-US');
|
138
|
+
expect(t('simpleText', {})).toBe('Just a simple text');
|
139
|
+
});
|
127
140
|
|
128
|
-
|
141
|
+
it('should handle missing parameters in translation string', async () => {
|
142
|
+
vi.doMock('@/../locales/en-US/common.json', async () => ({
|
143
|
+
withParam: 'Text with {{param}}',
|
144
|
+
}));
|
145
|
+
|
146
|
+
const { t } = await translation('common', 'en-US');
|
147
|
+
// 当缺少参数时应保留占位符
|
148
|
+
expect(t('withParam')).toBe('Text with {{param}}');
|
129
149
|
});
|
130
150
|
});
|