@lobehub/chat 1.74.2 → 1.74.3
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 +33 -0
- package/changelog/v1.json +9 -0
- package/docs/developer/database-schema.dbml +54 -2
- package/locales/ar/common.json +51 -0
- package/locales/ar/models.json +69 -3
- package/locales/ar/providers.json +6 -0
- package/locales/bg-BG/common.json +51 -0
- package/locales/bg-BG/models.json +69 -3
- package/locales/bg-BG/providers.json +6 -0
- package/locales/de-DE/common.json +51 -0
- package/locales/de-DE/models.json +69 -3
- package/locales/de-DE/providers.json +6 -0
- package/locales/en-US/common.json +51 -0
- package/locales/en-US/models.json +69 -3
- package/locales/en-US/providers.json +6 -3
- package/locales/es-ES/common.json +51 -0
- package/locales/es-ES/models.json +69 -3
- package/locales/es-ES/providers.json +6 -0
- package/locales/fa-IR/common.json +51 -0
- package/locales/fa-IR/models.json +69 -3
- package/locales/fa-IR/providers.json +6 -0
- package/locales/fr-FR/common.json +51 -0
- package/locales/fr-FR/models.json +69 -3
- package/locales/fr-FR/providers.json +6 -0
- package/locales/it-IT/common.json +51 -0
- package/locales/it-IT/models.json +69 -3
- package/locales/it-IT/providers.json +6 -0
- package/locales/ja-JP/common.json +51 -0
- package/locales/ja-JP/models.json +78 -4
- package/locales/ja-JP/providers.json +6 -0
- package/locales/ko-KR/common.json +51 -0
- package/locales/ko-KR/models.json +69 -3
- package/locales/ko-KR/providers.json +6 -0
- package/locales/nl-NL/common.json +51 -0
- package/locales/nl-NL/models.json +69 -3
- package/locales/nl-NL/providers.json +6 -0
- package/locales/pl-PL/common.json +51 -0
- package/locales/pl-PL/models.json +69 -3
- package/locales/pl-PL/providers.json +6 -0
- package/locales/pt-BR/common.json +51 -0
- package/locales/pt-BR/models.json +69 -3
- package/locales/pt-BR/providers.json +6 -0
- package/locales/ru-RU/common.json +51 -0
- package/locales/ru-RU/models.json +69 -3
- package/locales/ru-RU/providers.json +6 -0
- package/locales/tr-TR/common.json +51 -0
- package/locales/tr-TR/models.json +69 -3
- package/locales/tr-TR/providers.json +6 -0
- package/locales/vi-VN/common.json +51 -0
- package/locales/vi-VN/models.json +69 -3
- package/locales/vi-VN/providers.json +6 -0
- package/locales/zh-CN/common.json +53 -2
- package/locales/zh-CN/models.json +79 -13
- package/locales/zh-CN/providers.json +6 -4
- package/locales/zh-TW/common.json +51 -0
- package/locales/zh-TW/models.json +81 -4
- package/locales/zh-TW/providers.json +6 -0
- package/package.json +1 -1
- package/packages/web-crawler/src/utils/__tests__/withTimeout.test.ts +0 -1
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +4 -0
- package/src/database/client/db.ts +102 -11
- package/src/database/client/migrations.json +38 -8
- package/src/database/migrations/0018_add_client_id_for_entities.sql +32 -0
- package/src/database/migrations/meta/0018_snapshot.json +4212 -0
- package/src/database/migrations/meta/_journal.json +7 -0
- package/src/database/models/drizzleMigration.ts +23 -0
- package/src/database/schemas/agent.ts +48 -31
- package/src/database/schemas/file.ts +32 -16
- package/src/database/schemas/message.ts +91 -54
- package/src/database/schemas/rag.ts +65 -32
- package/src/database/schemas/session.ts +6 -3
- package/src/database/schemas/topic.ts +31 -24
- package/src/features/InitClientDB/ErrorResult.tsx +53 -32
- package/src/features/InitClientDB/features/DatabaseRepair/Backup.tsx +77 -0
- package/src/features/InitClientDB/features/DatabaseRepair/Diagnosis.tsx +98 -0
- package/src/features/InitClientDB/features/DatabaseRepair/Repair.tsx +220 -0
- package/src/features/InitClientDB/features/DatabaseRepair/index.tsx +85 -0
- package/src/features/ModelSwitchPanel/index.tsx +13 -7
- package/src/locales/default/common.ts +53 -1
- package/src/store/global/actions/clientDb.ts +19 -3
- package/src/store/global/initialState.ts +6 -1
- package/src/store/global/selectors/clientDB.ts +43 -0
- package/src/store/global/selectors/index.ts +1 -0
- package/src/store/user/slices/settings/selectors/general.test.ts +90 -0
- package/src/types/clientDB.ts +13 -0
@@ -1,7 +1,14 @@
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
1
2
|
import { PgliteDatabase, drizzle } from 'drizzle-orm/pglite';
|
2
3
|
import { Md5 } from 'ts-md5';
|
3
4
|
|
4
|
-
import {
|
5
|
+
import { DrizzleMigrationModel } from '@/database/models/drizzleMigration';
|
6
|
+
import {
|
7
|
+
ClientDBLoadingProgress,
|
8
|
+
DatabaseLoadingState,
|
9
|
+
MigrationSQL,
|
10
|
+
MigrationTableItem,
|
11
|
+
} from '@/types/clientDB';
|
5
12
|
import { sleep } from '@/utils/sleep';
|
6
13
|
|
7
14
|
import * as schema from '../schemas';
|
@@ -9,10 +16,17 @@ import migrations from './migrations.json';
|
|
9
16
|
|
10
17
|
const pgliteSchemaHashCache = 'LOBE_CHAT_PGLITE_SCHEMA_HASH';
|
11
18
|
|
19
|
+
const DB_NAME = 'lobechat';
|
12
20
|
type DrizzleInstance = PgliteDatabase<typeof schema>;
|
13
21
|
|
22
|
+
interface onErrorState {
|
23
|
+
error: Error;
|
24
|
+
migrationTableItems: MigrationTableItem[];
|
25
|
+
migrationsSQL: MigrationSQL[];
|
26
|
+
}
|
27
|
+
|
14
28
|
export interface DatabaseLoadingCallbacks {
|
15
|
-
onError?: (error:
|
29
|
+
onError?: (error: onErrorState) => void;
|
16
30
|
onProgress?: (progress: ClientDBLoadingProgress) => void;
|
17
31
|
onStateChange?: (state: DatabaseLoadingState) => void;
|
18
32
|
}
|
@@ -152,8 +166,28 @@ export class DatabaseManager {
|
|
152
166
|
hash = Md5.hashStr(JSON.stringify(migrations));
|
153
167
|
// if hash is the same, no need to migrate
|
154
168
|
if (hash === cacheHash) {
|
155
|
-
|
156
|
-
|
169
|
+
try {
|
170
|
+
// 检查数据库中是否存在表
|
171
|
+
// 这里使用 pg_tables 系统表查询用户表数量
|
172
|
+
const tablesResult = await this.db.execute(
|
173
|
+
sql`
|
174
|
+
SELECT COUNT(*) as table_count
|
175
|
+
FROM information_schema.tables
|
176
|
+
WHERE table_schema = 'public'
|
177
|
+
`,
|
178
|
+
);
|
179
|
+
|
180
|
+
const tableCount = parseInt((tablesResult.rows[0] as any).table_count || '0', 10);
|
181
|
+
|
182
|
+
// 如果表数量大于0,则认为数据库已正确初始化
|
183
|
+
if (tableCount > 0) {
|
184
|
+
this.isLocalDBSchemaSynced = true;
|
185
|
+
return this.db;
|
186
|
+
}
|
187
|
+
} catch (error) {
|
188
|
+
console.warn('Error checking table existence, proceeding with migration', error);
|
189
|
+
// 如果查询失败,继续执行迁移以确保安全
|
190
|
+
}
|
157
191
|
}
|
158
192
|
}
|
159
193
|
|
@@ -204,13 +238,11 @@ export class DatabaseManager {
|
|
204
238
|
|
205
239
|
let db: typeof PGlite;
|
206
240
|
|
207
|
-
const dbName = 'lobechat';
|
208
|
-
|
209
241
|
// make db as web worker if worker is available
|
210
242
|
// https://github.com/lobehub/lobe-chat/issues/5785
|
211
243
|
if (typeof Worker !== 'undefined' && typeof navigator.locks !== 'undefined') {
|
212
244
|
db = await initPgliteWorker({
|
213
|
-
dbName,
|
245
|
+
dbName: DB_NAME,
|
214
246
|
fsBundle: fsBundle as Blob,
|
215
247
|
vectorBundlePath: DatabaseManager.VECTOR_CDN_URL,
|
216
248
|
wasmModule,
|
@@ -219,7 +251,7 @@ export class DatabaseManager {
|
|
219
251
|
// in edge runtime or test runtime, we don't have worker
|
220
252
|
db = new PGlite({
|
221
253
|
extensions: { vector },
|
222
|
-
fs: typeof window === 'undefined' ? new MemoryFS(
|
254
|
+
fs: typeof window === 'undefined' ? new MemoryFS(DB_NAME) : new IdbFs(DB_NAME),
|
223
255
|
relaxedDurability: true,
|
224
256
|
wasmModule,
|
225
257
|
});
|
@@ -241,10 +273,25 @@ export class DatabaseManager {
|
|
241
273
|
this.initPromise = null;
|
242
274
|
this.callbacks?.onStateChange?.(DatabaseLoadingState.Error);
|
243
275
|
const error = e as Error;
|
276
|
+
|
277
|
+
// 查询迁移表数据
|
278
|
+
let migrationsTableData: MigrationTableItem[] = [];
|
279
|
+
try {
|
280
|
+
// 尝试查询迁移表
|
281
|
+
const drizzleMigration = new DrizzleMigrationModel(this.db as any);
|
282
|
+
migrationsTableData = await drizzleMigration.getMigrationList();
|
283
|
+
} catch (queryError) {
|
284
|
+
console.error('Failed to query migrations table:', queryError);
|
285
|
+
}
|
286
|
+
|
244
287
|
this.callbacks?.onError?.({
|
245
|
-
|
246
|
-
|
247
|
-
|
288
|
+
error: {
|
289
|
+
message: error.message,
|
290
|
+
name: error.name,
|
291
|
+
stack: error.stack,
|
292
|
+
},
|
293
|
+
migrationTableItems: migrationsTableData,
|
294
|
+
migrationsSQL: migrations,
|
248
295
|
});
|
249
296
|
|
250
297
|
console.error(error);
|
@@ -271,6 +318,38 @@ export class DatabaseManager {
|
|
271
318
|
},
|
272
319
|
});
|
273
320
|
}
|
321
|
+
|
322
|
+
async resetDatabase(): Promise<void> {
|
323
|
+
// 删除 IndexedDB 数据库
|
324
|
+
return new Promise<void>((resolve, reject) => {
|
325
|
+
// 检查 IndexedDB 是否可用
|
326
|
+
if (typeof indexedDB === 'undefined') {
|
327
|
+
console.warn('IndexedDB is not available, cannot delete database');
|
328
|
+
resolve();
|
329
|
+
return;
|
330
|
+
}
|
331
|
+
|
332
|
+
const dbName = `/pglite/${DB_NAME}`;
|
333
|
+
const request = indexedDB.deleteDatabase(dbName);
|
334
|
+
|
335
|
+
request.onsuccess = () => {
|
336
|
+
console.log(`✅ Database '${dbName}' reset successfully`);
|
337
|
+
|
338
|
+
// 清除本地存储的模式哈希
|
339
|
+
if (typeof localStorage !== 'undefined') {
|
340
|
+
localStorage.removeItem(pgliteSchemaHashCache);
|
341
|
+
}
|
342
|
+
|
343
|
+
resolve();
|
344
|
+
};
|
345
|
+
|
346
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
347
|
+
request.onerror = (event) => {
|
348
|
+
console.error('❌ Error resetting database:', event);
|
349
|
+
reject(new Error(`Failed to reset database '${dbName}'`));
|
350
|
+
};
|
351
|
+
});
|
352
|
+
}
|
274
353
|
}
|
275
354
|
|
276
355
|
// 导出单例
|
@@ -282,3 +361,15 @@ export const clientDB = dbManager.createProxy();
|
|
282
361
|
// 导出初始化方法,供应用启动时使用
|
283
362
|
export const initializeDB = (callbacks?: DatabaseLoadingCallbacks) =>
|
284
363
|
dbManager.initialize(callbacks);
|
364
|
+
|
365
|
+
export const resetClientDatabase = async () => {
|
366
|
+
await dbManager.resetDatabase();
|
367
|
+
};
|
368
|
+
|
369
|
+
export const updateMigrationRecord = async (migrationHash: string) => {
|
370
|
+
await clientDB.execute(
|
371
|
+
sql`INSERT INTO "drizzle"."__drizzle_migrations" ("hash", "created_at") VALUES (${migrationHash}, ${Date.now()});`,
|
372
|
+
);
|
373
|
+
|
374
|
+
await initializeDB();
|
375
|
+
};
|
@@ -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"
|
@@ -385,5 +380,40 @@
|
|
385
380
|
"bps": true,
|
386
381
|
"folderMillis": 1742269437903,
|
387
382
|
"hash": "89e91285be422d5f44511c7405f57b57f8dfda4f0304126ae9b0f266e5fd60f1"
|
383
|
+
},
|
384
|
+
{
|
385
|
+
"sql": [
|
386
|
+
"ALTER TABLE \"session_groups\" DROP CONSTRAINT \"session_group_client_id_user_unique\";",
|
387
|
+
"\nALTER TABLE \"sessions\" DROP CONSTRAINT \"sessions_client_id_user_id_unique\";",
|
388
|
+
"\nALTER TABLE \"topics\" DROP CONSTRAINT \"topic_client_id_user_id_unique\";",
|
389
|
+
"\nALTER TABLE \"agents\" ADD COLUMN \"client_id\" text;",
|
390
|
+
"\nALTER TABLE \"files\" ADD COLUMN \"client_id\" text;",
|
391
|
+
"\nALTER TABLE \"knowledge_bases\" ADD COLUMN \"client_id\" text;",
|
392
|
+
"\nALTER TABLE \"message_plugins\" ADD COLUMN \"client_id\" text;",
|
393
|
+
"\nALTER TABLE \"message_queries\" ADD COLUMN \"client_id\" text;",
|
394
|
+
"\nALTER TABLE \"message_tts\" ADD COLUMN \"client_id\" text;",
|
395
|
+
"\nALTER TABLE \"message_translates\" ADD COLUMN \"client_id\" text;",
|
396
|
+
"\nALTER TABLE \"chunks\" ADD COLUMN \"client_id\" text;",
|
397
|
+
"\nALTER TABLE \"embeddings\" ADD COLUMN \"client_id\" text;",
|
398
|
+
"\nALTER TABLE \"unstructured_chunks\" ADD COLUMN \"client_id\" text;",
|
399
|
+
"\nALTER TABLE \"threads\" ADD COLUMN \"client_id\" text;",
|
400
|
+
"\nCREATE UNIQUE INDEX \"client_id_user_id_unique\" ON \"agents\" USING btree (\"client_id\",\"user_id\");",
|
401
|
+
"\nCREATE UNIQUE INDEX \"files_client_id_user_id_unique\" ON \"files\" USING btree (\"client_id\",\"user_id\");",
|
402
|
+
"\nCREATE UNIQUE INDEX \"knowledge_bases_client_id_user_id_unique\" ON \"knowledge_bases\" USING btree (\"client_id\",\"user_id\");",
|
403
|
+
"\nCREATE UNIQUE INDEX \"message_plugins_client_id_user_id_unique\" ON \"message_plugins\" USING btree (\"client_id\",\"user_id\");",
|
404
|
+
"\nCREATE UNIQUE INDEX \"message_queries_client_id_user_id_unique\" ON \"message_queries\" USING btree (\"client_id\",\"user_id\");",
|
405
|
+
"\nCREATE UNIQUE INDEX \"message_tts_client_id_user_id_unique\" ON \"message_tts\" USING btree (\"client_id\",\"user_id\");",
|
406
|
+
"\nCREATE UNIQUE INDEX \"message_translates_client_id_user_id_unique\" ON \"message_translates\" USING btree (\"client_id\",\"user_id\");",
|
407
|
+
"\nCREATE UNIQUE INDEX \"chunks_client_id_user_id_unique\" ON \"chunks\" USING btree (\"client_id\",\"user_id\");",
|
408
|
+
"\nCREATE UNIQUE INDEX \"embeddings_client_id_user_id_unique\" ON \"embeddings\" USING btree (\"client_id\",\"user_id\");",
|
409
|
+
"\nCREATE UNIQUE INDEX \"unstructured_chunks_client_id_user_id_unique\" ON \"unstructured_chunks\" USING btree (\"client_id\",\"user_id\");",
|
410
|
+
"\nCREATE UNIQUE INDEX \"session_groups_client_id_user_id_unique\" ON \"session_groups\" USING btree (\"client_id\",\"user_id\");",
|
411
|
+
"\nCREATE UNIQUE INDEX \"sessions_client_id_user_id_unique\" ON \"sessions\" USING btree (\"client_id\",\"user_id\");",
|
412
|
+
"\nCREATE UNIQUE INDEX \"threads_client_id_user_id_unique\" ON \"threads\" USING btree (\"client_id\",\"user_id\");",
|
413
|
+
"\nCREATE UNIQUE INDEX \"topics_client_id_user_id_unique\" ON \"topics\" USING btree (\"client_id\",\"user_id\");"
|
414
|
+
],
|
415
|
+
"bps": true,
|
416
|
+
"folderMillis": 1742616026643,
|
417
|
+
"hash": "f885f1b1467b6564498f0d54ac2366c2d596f59bdd63a0feb63810c2ba346ae5"
|
388
418
|
}
|
389
|
-
]
|
419
|
+
]
|
@@ -0,0 +1,32 @@
|
|
1
|
+
ALTER TABLE "session_groups" DROP CONSTRAINT IF EXISTS "session_group_client_id_user_unique";--> statement-breakpoint
|
2
|
+
ALTER TABLE "sessions" DROP CONSTRAINT IF EXISTS "sessions_client_id_user_id_unique";--> statement-breakpoint
|
3
|
+
ALTER TABLE "topics" DROP CONSTRAINT IF EXISTS "topic_client_id_user_id_unique";--> statement-breakpoint
|
4
|
+
|
5
|
+
-- add client_id column
|
6
|
+
ALTER TABLE "agents" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
7
|
+
ALTER TABLE "files" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
8
|
+
ALTER TABLE "knowledge_bases" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
9
|
+
ALTER TABLE "message_plugins" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
10
|
+
ALTER TABLE "message_queries" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
11
|
+
ALTER TABLE "message_tts" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
12
|
+
ALTER TABLE "message_translates" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
13
|
+
ALTER TABLE "chunks" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
14
|
+
ALTER TABLE "embeddings" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
15
|
+
ALTER TABLE "unstructured_chunks" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
16
|
+
ALTER TABLE "threads" ADD COLUMN IF NOT EXISTS "client_id" text;--> statement-breakpoint
|
17
|
+
|
18
|
+
-- Create unique index(using IF NOT EXISTS)
|
19
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "client_id_user_id_unique" ON "agents" USING btree ("client_id","user_id");--> statement-breakpoint
|
20
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "files_client_id_user_id_unique" ON "files" USING btree ("client_id","user_id");--> statement-breakpoint
|
21
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "knowledge_bases_client_id_user_id_unique" ON "knowledge_bases" USING btree ("client_id","user_id");--> statement-breakpoint
|
22
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "message_plugins_client_id_user_id_unique" ON "message_plugins" USING btree ("client_id","user_id");--> statement-breakpoint
|
23
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "message_queries_client_id_user_id_unique" ON "message_queries" USING btree ("client_id","user_id");--> statement-breakpoint
|
24
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "message_tts_client_id_user_id_unique" ON "message_tts" USING btree ("client_id","user_id");--> statement-breakpoint
|
25
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "message_translates_client_id_user_id_unique" ON "message_translates" USING btree ("client_id","user_id");--> statement-breakpoint
|
26
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "chunks_client_id_user_id_unique" ON "chunks" USING btree ("client_id","user_id");--> statement-breakpoint
|
27
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "embeddings_client_id_user_id_unique" ON "embeddings" USING btree ("client_id","user_id");--> statement-breakpoint
|
28
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "unstructured_chunks_client_id_user_id_unique" ON "unstructured_chunks" USING btree ("client_id","user_id");--> statement-breakpoint
|
29
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "session_groups_client_id_user_id_unique" ON "session_groups" USING btree ("client_id","user_id");--> statement-breakpoint
|
30
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "sessions_client_id_user_id_unique" ON "sessions" USING btree ("client_id","user_id");--> statement-breakpoint
|
31
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "threads_client_id_user_id_unique" ON "threads" USING btree ("client_id","user_id");--> statement-breakpoint
|
32
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "topics_client_id_user_id_unique" ON "topics" USING btree ("client_id","user_id");
|