@lobehub/lobehub 2.0.0-next.143 → 2.0.0-next.144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/package.json +1 -1
- package/packages/database/migrations/0054_better_auth_two_factor.sql +2 -0
- package/packages/database/src/core/migrations.json +1 -1
- package/packages/database/src/models/user.ts +25 -5
- package/scripts/migrateServerDB/errorHint.js +26 -0
- package/scripts/migrateServerDB/index.ts +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.144](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.143...v2.0.0-next.144)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-12-02**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: User email unique migration error.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: User email unique migration error, closes [#10548](https://github.com/lobehub/lobe-chat/issues/10548) ([ca2a1a2](https://github.com/lobehub/lobe-chat/commit/ca2a1a2))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 2.0.0-next.143](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.142...v2.0.0-next.143)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2025-12-02**</sup>
|
package/changelog/v1.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.144",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -35,6 +35,8 @@ CREATE INDEX IF NOT EXISTS "verification_identifier_idx" ON "verifications" USIN
|
|
|
35
35
|
DO $$
|
|
36
36
|
BEGIN
|
|
37
37
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_email_unique') THEN
|
|
38
|
+
-- Normalize empty emails so the unique constraint can be created safely
|
|
39
|
+
UPDATE "users" SET "email" = NULL WHERE "email" = '';
|
|
38
40
|
ALTER TABLE "users" ADD CONSTRAINT "users_email_unique" UNIQUE ("email");
|
|
39
41
|
END IF;
|
|
40
42
|
END $$;
|
|
@@ -884,7 +884,7 @@
|
|
|
884
884
|
"\nCREATE INDEX IF NOT EXISTS \"account_userId_idx\" ON \"accounts\" USING btree (\"user_id\");\n",
|
|
885
885
|
"\nCREATE INDEX IF NOT EXISTS \"auth_session_userId_idx\" ON \"auth_sessions\" USING btree (\"user_id\");\n",
|
|
886
886
|
"\nCREATE INDEX IF NOT EXISTS \"verification_identifier_idx\" ON \"verifications\" USING btree (\"identifier\");\n",
|
|
887
|
-
"\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_email_unique') THEN\n ALTER TABLE \"users\" ADD CONSTRAINT \"users_email_unique\" UNIQUE (\"email\");\n END IF;\nEND $$;\n",
|
|
887
|
+
"\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_email_unique') THEN\n UPDATE \"users\" SET \"email\" = NULL WHERE \"email\" = '';\n ALTER TABLE \"users\" ADD CONSTRAINT \"users_email_unique\" UNIQUE (\"email\");\n END IF;\nEND $$;\n",
|
|
888
888
|
"\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'users_phone_number_unique') THEN\n ALTER TABLE \"users\" ADD CONSTRAINT \"users_phone_number_unique\" UNIQUE (\"phone_number\");\n END IF;\nEND $$;\n"
|
|
889
889
|
],
|
|
890
890
|
"bps": true,
|
|
@@ -149,9 +149,11 @@ export class UserModel {
|
|
|
149
149
|
};
|
|
150
150
|
|
|
151
151
|
updateUser = async (value: Partial<UserItem>) => {
|
|
152
|
+
const nextValue = UserModel.normalizeUniqueUserFields(value);
|
|
153
|
+
|
|
152
154
|
return this.db
|
|
153
155
|
.update(users)
|
|
154
|
-
.set({ ...
|
|
156
|
+
.set({ ...nextValue, updatedAt: new Date() })
|
|
155
157
|
.where(eq(users.id, this.userId));
|
|
156
158
|
};
|
|
157
159
|
|
|
@@ -193,6 +195,26 @@ export class UserModel {
|
|
|
193
195
|
.where(eq(users.id, this.userId));
|
|
194
196
|
};
|
|
195
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Normalize unique user fields so empty strings become null, keeping unique constraints safe.
|
|
200
|
+
*/
|
|
201
|
+
private static normalizeUniqueUserFields = <
|
|
202
|
+
T extends { email?: string | null; phone?: string | null },
|
|
203
|
+
>(
|
|
204
|
+
value: T,
|
|
205
|
+
) => {
|
|
206
|
+
const normalizedEmail =
|
|
207
|
+
typeof value.email === 'string' && value.email.trim() === '' ? null : value.email;
|
|
208
|
+
const normalizedPhone =
|
|
209
|
+
typeof value.phone === 'string' && value.phone.trim() === '' ? null : value.phone;
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
...value,
|
|
213
|
+
...(value.email !== undefined ? { email: normalizedEmail } : {}),
|
|
214
|
+
...(value.phone !== undefined ? { phone: normalizedPhone } : {}),
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
196
218
|
// Static method
|
|
197
219
|
static makeSureUserExist = async (db: LobeChatDatabase, userId: string) => {
|
|
198
220
|
await db.insert(users).values({ id: userId }).onConflictDoNothing();
|
|
@@ -205,10 +227,8 @@ export class UserModel {
|
|
|
205
227
|
if (!!user) return { duplicate: true };
|
|
206
228
|
}
|
|
207
229
|
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
.values({ ...params })
|
|
211
|
-
.returning();
|
|
230
|
+
const normalizedParams = this.normalizeUniqueUserFields(params);
|
|
231
|
+
const [user] = await db.insert(users).values(normalizedParams).returning();
|
|
212
232
|
|
|
213
233
|
return { duplicate: false, user };
|
|
214
234
|
};
|
|
@@ -24,7 +24,33 @@ DATABASE_DRIVER=node
|
|
|
24
24
|
if you have any other question, please open issue here: https://github.com/lobehub/lobe-chat/issues
|
|
25
25
|
`;
|
|
26
26
|
|
|
27
|
+
const DUPLICATE_EMAIL_HINT = `------------------------------------------------------------------------------------------
|
|
28
|
+
⚠️ Database migration failed due to duplicate email addresses in the users table.
|
|
29
|
+
|
|
30
|
+
The database schema requires each email to be unique, but multiple users currently share the same email value.
|
|
31
|
+
|
|
32
|
+
Recommended solutions (choose one and rerun the migration):
|
|
33
|
+
|
|
34
|
+
1) Update duplicate emails to make them unique: change the conflicting email addresses to another unique email address or just change them email to NULL
|
|
35
|
+
2) Remove duplicate user records (dangerously, only if safe to delete)
|
|
36
|
+
|
|
37
|
+
⚠️ IMPORTANT: Always backup your database before making any changes!
|
|
38
|
+
|
|
39
|
+
To find duplicate emails, run this query:
|
|
40
|
+
|
|
41
|
+
\`\`\`sql
|
|
42
|
+
SELECT email, COUNT(*) as count
|
|
43
|
+
FROM users
|
|
44
|
+
WHERE email IS NOT NULL
|
|
45
|
+
GROUP BY email
|
|
46
|
+
HAVING COUNT(*) > 1;
|
|
47
|
+
\`\`\`
|
|
48
|
+
|
|
49
|
+
If you need further assistance, please open an issue: https://github.com/lobehub/lobe-chat/issues
|
|
50
|
+
`;
|
|
51
|
+
|
|
27
52
|
module.exports = {
|
|
28
53
|
DB_FAIL_INIT_HINT,
|
|
54
|
+
DUPLICATE_EMAIL_HINT,
|
|
29
55
|
PGVECTOR_HINT,
|
|
30
56
|
};
|
|
@@ -4,7 +4,7 @@ import { migrate as nodeMigrate } from 'drizzle-orm/node-postgres/migrator';
|
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
|
|
6
6
|
// @ts-ignore tsgo handle esm import cjs and compatibility issues
|
|
7
|
-
import { DB_FAIL_INIT_HINT, PGVECTOR_HINT } from './errorHint';
|
|
7
|
+
import { DB_FAIL_INIT_HINT, DUPLICATE_EMAIL_HINT, PGVECTOR_HINT } from './errorHint';
|
|
8
8
|
|
|
9
9
|
// Read the `.env` file if it exists, or a file specified by the
|
|
10
10
|
// dotenv_config_path parameter that's passed to Node.js
|
|
@@ -39,8 +39,12 @@ if (!isDesktop && connectionString) {
|
|
|
39
39
|
|
|
40
40
|
const errMsg = err.message as string;
|
|
41
41
|
|
|
42
|
+
const constraint = (err as { constraint?: string })?.constraint;
|
|
43
|
+
|
|
42
44
|
if (errMsg.includes('extension "vector" is not available')) {
|
|
43
45
|
console.info(PGVECTOR_HINT);
|
|
46
|
+
} else if (constraint === 'users_email_unique' || errMsg.includes('users_email_unique')) {
|
|
47
|
+
console.info(DUPLICATE_EMAIL_HINT);
|
|
44
48
|
} else if (errMsg.includes(`Cannot read properties of undefined (reading 'migrate')`)) {
|
|
45
49
|
console.info(DB_FAIL_INIT_HINT);
|
|
46
50
|
}
|