@lobehub/lobehub 2.0.0-next.196 → 2.0.0-next.197

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/changelog/v1.json +12 -0
  3. package/package.json +2 -3
  4. package/packages/database/src/core/getTestDB.ts +50 -0
  5. package/packages/database/src/models/__tests__/_test_template.ts +1 -1
  6. package/packages/database/src/models/__tests__/agent.test.ts +1 -1
  7. package/packages/database/src/models/__tests__/aiModel.test.ts +1 -1
  8. package/packages/database/src/models/__tests__/aiProvider.test.ts +1 -1
  9. package/packages/database/src/models/__tests__/apiKey.test.ts +1 -1
  10. package/packages/database/src/models/__tests__/asyncTask.test.ts +1 -1
  11. package/packages/database/src/models/__tests__/chatGroup.test.ts +1 -1
  12. package/packages/database/src/models/__tests__/chunk.test.ts +1 -1
  13. package/packages/database/src/models/__tests__/document.test.ts +1 -1
  14. package/packages/database/src/models/__tests__/drizzleMigration.test.ts +1 -1
  15. package/packages/database/src/models/__tests__/embedding.test.ts +1 -1
  16. package/packages/database/src/models/__tests__/file.test.ts +1 -1
  17. package/packages/database/src/models/__tests__/generation.test.ts +1 -1
  18. package/packages/database/src/models/__tests__/generationBatch.test.ts +1 -1
  19. package/packages/database/src/models/__tests__/generationTopic.test.ts +1 -1
  20. package/packages/database/src/models/__tests__/knowledgeBase.test.ts +1 -1
  21. package/packages/database/src/models/__tests__/messages/message.create.test.ts +1 -1
  22. package/packages/database/src/models/__tests__/messages/message.delete.test.ts +1 -1
  23. package/packages/database/src/models/__tests__/messages/message.query.test.ts +1 -1
  24. package/packages/database/src/models/__tests__/messages/message.stats.test.ts +1 -1
  25. package/packages/database/src/models/__tests__/messages/message.thread-query.test.ts +1 -1
  26. package/packages/database/src/models/__tests__/messages/message.update.test.ts +1 -1
  27. package/packages/database/src/models/__tests__/messages/messageWithTask.test.ts +1 -1
  28. package/packages/database/src/models/__tests__/messages/queryWithMessageGroup.perf.test.ts +1 -1
  29. package/packages/database/src/models/__tests__/messages/queryWithMessageGroup.test.ts +1 -1
  30. package/packages/database/src/models/__tests__/oauthHandoff.test.ts +1 -1
  31. package/packages/database/src/models/__tests__/plugin.test.ts +1 -1
  32. package/packages/database/src/models/__tests__/session.test.ts +1 -1
  33. package/packages/database/src/models/__tests__/sessionGroup.test.ts +1 -1
  34. package/packages/database/src/models/__tests__/thread.test.ts +1 -1
  35. package/packages/database/src/models/__tests__/topicDocument.test.ts +1 -1
  36. package/packages/database/src/models/__tests__/topics/topic.create.test.ts +1 -1
  37. package/packages/database/src/models/__tests__/topics/topic.delete.test.ts +1 -1
  38. package/packages/database/src/models/__tests__/topics/topic.query.test.ts +1 -1
  39. package/packages/database/src/models/__tests__/topics/topic.stats.test.ts +1 -1
  40. package/packages/database/src/models/__tests__/topics/topic.update.test.ts +1 -1
  41. package/packages/database/src/models/__tests__/user.test.ts +1 -1
  42. package/packages/database/src/models/__tests__/userMemories.test.ts +1 -1
  43. package/packages/database/src/models/__tests__/userMemoryIdentity.test.ts +1 -1
  44. package/packages/database/src/models/userMemory/__tests__/context.test.ts +1 -1
  45. package/packages/database/src/models/userMemory/__tests__/experience.test.ts +1 -1
  46. package/packages/database/src/models/userMemory/__tests__/identity.test.ts +1 -1
  47. package/packages/database/src/models/userMemory/__tests__/preference.test.ts +1 -1
  48. package/packages/database/src/repositories/agentGroup/index.test.ts +1 -1
  49. package/packages/database/src/repositories/agentMigration/__tests__/agentMigrationRepo.test.ts +1 -1
  50. package/packages/database/src/repositories/aiInfra/index.test.ts +1 -1
  51. package/packages/database/src/repositories/compression/index.test.ts +1 -1
  52. package/packages/database/src/repositories/dataExporter/index.test.ts +1 -1
  53. package/packages/database/src/repositories/dataImporter/__tests__/index.test.ts +1 -1
  54. package/packages/database/src/repositories/dataImporter/deprecated/__tests__/index.test.ts +2 -2
  55. package/packages/database/src/repositories/home/__tests__/index.test.ts +1 -1
  56. package/packages/database/src/repositories/home/index.test.ts +1 -1
  57. package/packages/database/src/repositories/knowledge/index.test.ts +1 -1
  58. package/packages/database/src/repositories/search/index.test.ts +1 -1
  59. package/packages/database/src/repositories/topicImporter/__tests__/importTopic.test.ts +1 -1
  60. package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +1 -1
  61. package/packages/database/src/server/models/__tests__/adapter.test.ts +2 -2
  62. package/packages/database/src/server/models/__tests__/user.test.ts +2 -2
  63. package/packages/database/tests/test-utils.ts +1 -1
  64. package/packages/types/src/export.ts +1 -1
  65. package/packages/types/src/index.ts +0 -1
  66. package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +1 -0
  67. package/src/features/LibraryModal/AssignKnowledgeBase/List.tsx +12 -13
  68. package/src/features/ResourceManager/components/Explorer/MasonryView/index.tsx +1 -0
  69. package/src/server/routers/lambda/__tests__/file.test.ts +76 -3
  70. package/src/server/routers/lambda/file.ts +13 -1
  71. package/src/services/config.ts +2 -16
  72. package/packages/database/src/core/dbForTest.ts +0 -43
  73. package/packages/database/src/core/migrations.json +0 -1080
  74. package/packages/database/src/models/__tests__/_util.ts +0 -30
  75. package/packages/database/src/repositories/tableViewer/index.test.ts +0 -255
  76. package/packages/database/src/repositories/tableViewer/index.ts +0 -251
  77. package/packages/types/src/tableViewer.ts +0 -30
  78. package/scripts/migrateClientDB/compile-migrations.ts +0 -14
@@ -2,7 +2,7 @@ import type { ImportPgDataStructure } from '@lobechat/types';
2
2
  import { eq, inArray } from 'drizzle-orm';
3
3
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
4
 
5
- import { getTestDB } from '../../../models/__tests__/_util';
5
+ import { getTestDB } from '../../../core/getTestDB';
6
6
  import * as Schema from '../../../schemas';
7
7
  import { DataImporterRepos } from '../index';
8
8
  import agentsData from './fixtures/agents.json';
@@ -3,7 +3,7 @@ import type { ImporterEntryData } from '@lobechat/types';
3
3
  import { eq, inArray } from 'drizzle-orm';
4
4
  import { beforeEach, describe, expect, it, vi } from 'vitest';
5
5
 
6
- import { getTestDBInstance } from '@/database/core/dbForTest';
6
+ import { getTestDB } from '../../../../core/getTestDB';
7
7
  import {
8
8
  agents,
9
9
  agentsToSessions,
@@ -19,7 +19,7 @@ import mockImportData from './fixtures/messages.json';
19
19
 
20
20
  const CURRENT_CONFIG_VERSION = 7;
21
21
 
22
- const serverDB = await getTestDBInstance();
22
+ const serverDB = await getTestDB();
23
23
 
24
24
  const userId = 'test-user-id';
25
25
  let importer: DataImporterRepos;
@@ -1,7 +1,7 @@
1
1
  import { eq } from 'drizzle-orm';
2
2
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
3
3
 
4
- import { getTestDB } from '../../../models/__tests__/_util';
4
+ import { getTestDB } from '../../../core/getTestDB';
5
5
  import * as Schema from '../../../schemas';
6
6
  import { HomeRepository } from '../index';
7
7
 
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment node
2
2
  import { beforeEach, describe, expect, it } from 'vitest';
3
3
 
4
- import { getTestDB } from '../../models/__tests__/_util';
4
+ import { getTestDB } from '../../core/getTestDB';
5
5
  import { NewAgent, agents } from '../../schemas/agent';
6
6
  import { NewChatGroup, chatGroups } from '../../schemas/chatGroup';
7
7
  import { agentsToSessions } from '../../schemas/relations';
@@ -2,7 +2,7 @@
2
2
  import { FilesTabs } from '@lobechat/types';
3
3
  import { beforeEach, describe, expect, it } from 'vitest';
4
4
 
5
- import { getTestDB } from '../../models/__tests__/_util';
5
+ import { getTestDB } from '../../core/getTestDB';
6
6
  import { NewDocument, documents } from '../../schemas/file';
7
7
  import { NewFile, files } from '../../schemas/file';
8
8
  import { users } from '../../schemas/user';
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment node
2
2
  import { beforeEach, describe, expect, it } from 'vitest';
3
3
 
4
- import { getTestDB } from '../../models/__tests__/_util';
4
+ import { getTestDB } from '../../core/getTestDB';
5
5
  import { NewAgent, agents } from '../../schemas/agent';
6
6
  import { NewFile, files } from '../../schemas/file';
7
7
  import { messages } from '../../schemas/message';
@@ -4,7 +4,7 @@ import { readFileSync } from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
6
 
7
- import { getTestDB } from '../../../models/__tests__/_util';
7
+ import { getTestDB } from '../../../core/getTestDB';
8
8
  import { agents, messagePlugins, messages, topics, users } from '../../../schemas';
9
9
  import { LobeChatDatabase } from '../../../type';
10
10
  import { TopicImporterRepo } from '../index';
@@ -1,7 +1,7 @@
1
1
  // @vitest-environment node
2
2
  import { beforeEach, describe, expect, it } from 'vitest';
3
3
 
4
- import { getTestDB } from '../../../models/__tests__/_util';
4
+ import { getTestDB } from '../../../core/getTestDB';
5
5
  import { messages } from '../../../schemas/message';
6
6
  import { topics } from '../../../schemas/topic';
7
7
  import { users } from '../../../schemas/user';
@@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
3
3
 
4
4
  import { DrizzleAdapter } from '@/libs/oidc-provider/adapter';
5
5
 
6
- import { getTestDBInstance } from '../../../core/dbForTest';
6
+ import { getTestDB } from '../../../core/getTestDB';
7
7
  import { users } from '../../../schemas';
8
8
  import {
9
9
  oidcAccessTokens,
@@ -14,7 +14,7 @@ import {
14
14
  oidcSessions,
15
15
  } from '../../../schemas/oidc';
16
16
 
17
- let serverDB = await getTestDBInstance();
17
+ let serverDB = await getTestDB();
18
18
 
19
19
  // Test data
20
20
  const testModelName = 'Session';
@@ -7,12 +7,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
7
7
 
8
8
  import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
9
9
 
10
- import { getTestDBInstance } from '../../../core/dbForTest';
10
+ import { getTestDB } from '../../../core/getTestDB';
11
11
  import { SessionModel } from '../../../models/session';
12
12
  import { UserModel, UserNotFoundError } from '../../../models/user';
13
13
  import { UserSettingsItem, nextauthAccounts, userSettings, users } from '../../../schemas';
14
14
 
15
- let serverDB = await getTestDBInstance();
15
+ let serverDB = await getTestDB();
16
16
 
17
17
  const userId = 'user-db';
18
18
  const userEmail = 'user@example.com';
@@ -1 +1 @@
1
- export * from '../src/models/__tests__/_util';
1
+ export * from '../src/core/getTestDB';
@@ -1,6 +1,6 @@
1
1
  export interface ExportDatabaseData {
2
2
  data: Record<string, object[]>;
3
- schemaHash?: string;
3
+ schemaHash: string;
4
4
  url?: string;
5
5
  }
6
6
 
@@ -29,7 +29,6 @@ export * from './serverConfig';
29
29
  export * from './service';
30
30
  export * from './session';
31
31
  export * from './stepContext';
32
- export * from './tableViewer';
33
32
  export * from './tool';
34
33
  export * from './topic';
35
34
  export * from './user';
@@ -52,6 +52,7 @@ const Token = memo<TokenTagProps>(({ total: messageString }) => {
52
52
  chatConfigByIdSelectors.getEnableHistoryCountById(agentId)(s),
53
53
  // need to re-render by search mode
54
54
  chatConfigByIdSelectors.isEnableSearchById(agentId)(s),
55
+ chatConfigByIdSelectors.getUseModelBuiltinSearchById(agentId)(s),
55
56
  ]);
56
57
 
57
58
  const maxTokens = useModelContextWindowTokens(model, provider);
@@ -114,19 +114,18 @@ export const List = memo(() => {
114
114
  totalCount={data!.length}
115
115
  />
116
116
  ) : (
117
- <div style={{ flex: 1, overflow: 'hidden' }}>
118
- <div style={{ height: '100%', overflowY: 'auto' }}>
119
- <div style={{ paddingInline: 16 }}>
120
- <VirtuosoMasonry
121
- ItemContent={MasonryItemWrapper}
122
- columnCount={columnCount}
123
- context={masonryContext}
124
- data={data || []}
125
- style={{
126
- gap: '16px',
127
- }}
128
- />
129
- </div>
117
+ <div style={{ height: '100%', position: 'relative' }}>
118
+ <div style={{ inset: 0, position: 'absolute' }}>
119
+ <VirtuosoMasonry
120
+ ItemContent={MasonryItemWrapper}
121
+ columnCount={columnCount}
122
+ context={masonryContext}
123
+ data={data || []}
124
+ style={{
125
+ gap: '16px',
126
+ height: '100%',
127
+ }}
128
+ />
130
129
  </div>
131
130
  </div>
132
131
  )}
@@ -87,6 +87,7 @@ const MasonryView = memo<MasonryViewProps>(
87
87
  data={data || []}
88
88
  style={{
89
89
  gap: '16px',
90
+ overflow: 'hidden',
90
91
  }}
91
92
  />
92
93
  {isLoadingMore && (
@@ -245,7 +245,35 @@ describe('fileRouter', () => {
245
245
  );
246
246
  });
247
247
 
248
- it('should handle getFileMetadata errors', async () => {
248
+ it('should fallback to input size when getFileMetadata fails', async () => {
249
+ mockFileModelCheckHash.mockResolvedValue({ isExist: false });
250
+ mockFileModelCreate.mockResolvedValue({ id: 'new-file-id' });
251
+ mockFileServiceGetFileMetadata.mockRejectedValue(new Error('File not found in S3'));
252
+
253
+ const result = await caller.createFile({
254
+ hash: 'test-hash',
255
+ fileType: 'text',
256
+ name: 'test.txt',
257
+ size: 100,
258
+ url: 'files/non-existent.txt',
259
+ metadata: {},
260
+ });
261
+
262
+ expect(result).toEqual({
263
+ id: 'new-file-id',
264
+ url: 'https://lobehub.com/f/new-file-id',
265
+ });
266
+
267
+ // Verify create was called with input size as fallback
268
+ expect(mockFileModelCreate).toHaveBeenCalledWith(
269
+ expect.objectContaining({
270
+ size: 100,
271
+ }),
272
+ true,
273
+ );
274
+ });
275
+
276
+ it('should throw error when getFileMetadata fails and input size is less than 1', async () => {
249
277
  mockFileModelCheckHash.mockResolvedValue({ isExist: false });
250
278
  mockFileServiceGetFileMetadata.mockRejectedValue(new Error('File not found in S3'));
251
279
 
@@ -254,11 +282,56 @@ describe('fileRouter', () => {
254
282
  hash: 'test-hash',
255
283
  fileType: 'text',
256
284
  name: 'test.txt',
257
- size: 100,
285
+ size: 0,
258
286
  url: 'files/non-existent.txt',
259
287
  metadata: {},
260
288
  }),
261
- ).rejects.toThrow('File not found in S3');
289
+ ).rejects.toThrow('File size must be at least 1 byte');
290
+ });
291
+
292
+ it('should use input size when getFileMetadata returns contentLength less than 1', async () => {
293
+ mockFileModelCheckHash.mockResolvedValue({ isExist: false });
294
+ mockFileModelCreate.mockResolvedValue({ id: 'new-file-id' });
295
+ mockFileServiceGetFileMetadata.mockResolvedValue({
296
+ contentLength: 0,
297
+ contentType: 'text/plain',
298
+ });
299
+
300
+ await caller.createFile({
301
+ hash: 'test-hash',
302
+ fileType: 'text',
303
+ name: 'test.txt',
304
+ size: 100,
305
+ url: 'files/test.txt',
306
+ metadata: {},
307
+ });
308
+
309
+ // Verify create was called with input size since contentLength < 1
310
+ expect(mockFileModelCreate).toHaveBeenCalledWith(
311
+ expect.objectContaining({
312
+ size: 100,
313
+ }),
314
+ true,
315
+ );
316
+ });
317
+
318
+ it('should throw error when both getFileMetadata contentLength and input size are less than 1', async () => {
319
+ mockFileModelCheckHash.mockResolvedValue({ isExist: false });
320
+ mockFileServiceGetFileMetadata.mockResolvedValue({
321
+ contentLength: 0,
322
+ contentType: 'text/plain',
323
+ });
324
+
325
+ await expect(
326
+ caller.createFile({
327
+ hash: 'test-hash',
328
+ fileType: 'text',
329
+ name: 'test.txt',
330
+ size: 0,
331
+ url: 'files/test.txt',
332
+ metadata: {},
333
+ }),
334
+ ).rejects.toThrow('File size must be at least 1 byte');
262
335
  });
263
336
  });
264
337
 
@@ -64,7 +64,19 @@ export const fileRouter = router({
64
64
  }
65
65
  }
66
66
 
67
- const { contentLength: actualSize } = await ctx.fileService.getFileMetadata(input.url);
67
+ let actualSize = input.size;
68
+ try {
69
+ const { contentLength } = await ctx.fileService.getFileMetadata(input.url);
70
+ if (contentLength >= 1) {
71
+ actualSize = contentLength;
72
+ }
73
+ } catch {
74
+ // If metadata fetch fails, use original size from input
75
+ }
76
+
77
+ if (actualSize < 1) {
78
+ throw new TRPCError({ code: 'BAD_REQUEST', message: 'File size must be at least 1 byte' });
79
+ }
68
80
 
69
81
  const { id } = await ctx.fileModel.create(
70
82
  {
@@ -8,7 +8,7 @@ import { exportService } from './export';
8
8
 
9
9
  class ConfigService {
10
10
  exportAll = async () => {
11
- const { data, url } = await exportService.exportData();
11
+ const { data, url, schemaHash } = await exportService.exportData();
12
12
  const filename = `${dayjs().format('YYYY-MM-DD-hh-mm')}_${BRANDING_NAME}-data.json`;
13
13
 
14
14
  // if url exists, means export data from server and upload the data to S3
@@ -18,24 +18,10 @@ class ConfigService {
18
18
  return;
19
19
  }
20
20
 
21
- // or export to file with the data
22
- const result = await this.createDataStructure(data, 'postgres');
21
+ const result: ImportPgDataStructure = { data, mode: 'postgres', schemaHash };
23
22
 
24
23
  exportJSONFile(result, filename);
25
24
  };
26
-
27
- private createDataStructure = async (
28
- data: any,
29
- mode: 'pglite' | 'postgres',
30
- ): Promise<ImportPgDataStructure> => {
31
- const { default: json } = await import('@/database/core/migrations.json');
32
- const latestHash = json.at(-1)?.hash;
33
- if (!latestHash) {
34
- throw new Error('Not find database sql hash');
35
- }
36
-
37
- return { data, mode, schemaHash: latestHash };
38
- };
39
25
  }
40
26
 
41
27
  export const configService = new ConfigService();
@@ -1,43 +0,0 @@
1
- import { Pool as NeonPool, neonConfig } from '@neondatabase/serverless';
2
- import { drizzle as neonDrizzle } from 'drizzle-orm/neon-serverless';
3
- import * as migrator from 'drizzle-orm/neon-serverless/migrator';
4
- import { drizzle as nodeDrizzle } from 'drizzle-orm/node-postgres';
5
- import * as nodeMigrator from 'drizzle-orm/node-postgres/migrator';
6
- import { join } from 'node:path';
7
- import { Pool as NodePool } from 'pg';
8
- import ws from 'ws';
9
-
10
- import { serverDBEnv } from '@/config/db';
11
-
12
- import * as schema from '../schemas';
13
-
14
- const migrationsFolder = join(__dirname, '../../migrations');
15
-
16
- export const getTestDBInstance = async () => {
17
- let connectionString = serverDBEnv.DATABASE_TEST_URL;
18
-
19
- if (!connectionString) {
20
- throw new Error(`You are try to use database, but "DATABASE_TEST_URL" is not set correctly`);
21
- }
22
-
23
- if (serverDBEnv.DATABASE_DRIVER === 'node') {
24
- const client = new NodePool({ connectionString });
25
-
26
- const db = nodeDrizzle(client, { schema });
27
-
28
- await nodeMigrator.migrate(db, { migrationsFolder });
29
-
30
- return db;
31
- }
32
-
33
- // https://github.com/neondatabase/serverless/blob/main/CONFIG.md#websocketconstructor-typeof-websocket--undefined
34
- neonConfig.webSocketConstructor = ws;
35
-
36
- const client = new NeonPool({ connectionString });
37
-
38
- const db = neonDrizzle(client, { schema });
39
-
40
- await migrator.migrate(db, { migrationsFolder });
41
-
42
- return db;
43
- };