@lobehub/lobehub 2.0.0-next.127 → 2.0.0-next.128

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 (46) hide show
  1. package/.env.example +23 -3
  2. package/.env.example.development +5 -0
  3. package/CHANGELOG.md +25 -0
  4. package/changelog/v1.json +9 -0
  5. package/docker-compose/local/docker-compose.yml +24 -1
  6. package/docker-compose/local/logto/docker-compose.yml +25 -2
  7. package/docker-compose.development.yml +6 -0
  8. package/locales/ar/auth.json +114 -1
  9. package/locales/bg-BG/auth.json +114 -1
  10. package/locales/de-DE/auth.json +114 -1
  11. package/locales/en-US/auth.json +42 -22
  12. package/locales/es-ES/auth.json +114 -1
  13. package/locales/fa-IR/auth.json +114 -1
  14. package/locales/fr-FR/auth.json +114 -1
  15. package/locales/it-IT/auth.json +114 -1
  16. package/locales/ja-JP/auth.json +114 -1
  17. package/locales/ko-KR/auth.json +114 -1
  18. package/locales/nl-NL/auth.json +114 -1
  19. package/locales/pl-PL/auth.json +114 -1
  20. package/locales/pt-BR/auth.json +114 -1
  21. package/locales/ru-RU/auth.json +114 -1
  22. package/locales/tr-TR/auth.json +114 -1
  23. package/locales/vi-VN/auth.json +114 -1
  24. package/locales/zh-CN/auth.json +36 -29
  25. package/locales/zh-TW/auth.json +114 -1
  26. package/package.json +4 -1
  27. package/packages/database/src/client/db.ts +21 -21
  28. package/packages/database/src/repositories/dataImporter/deprecated/index.ts +5 -5
  29. package/packages/database/src/repositories/dataImporter/index.ts +59 -59
  30. package/packages/database/src/schemas/generation.ts +16 -16
  31. package/packages/database/src/schemas/oidc.ts +36 -36
  32. package/packages/model-runtime/src/providers/newapi/index.ts +61 -18
  33. package/packages/model-runtime/src/runtimeMap.ts +1 -0
  34. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/UpdateProviderInfo/SettingModal.tsx +10 -6
  35. package/src/envs/redis.ts +106 -0
  36. package/src/libs/redis/index.ts +5 -0
  37. package/src/libs/redis/manager.test.ts +107 -0
  38. package/src/libs/redis/manager.ts +56 -0
  39. package/src/libs/redis/redis.test.ts +158 -0
  40. package/src/libs/redis/redis.ts +117 -0
  41. package/src/libs/redis/types.ts +71 -0
  42. package/src/libs/redis/upstash.test.ts +154 -0
  43. package/src/libs/redis/upstash.ts +109 -0
  44. package/src/libs/redis/utils.test.ts +46 -0
  45. package/src/libs/redis/utils.ts +53 -0
  46. package/.github/workflows/check-console-log.yml +0 -117
@@ -52,6 +52,104 @@
52
52
  "required": "Nội dung không được để trống"
53
53
  }
54
54
  },
55
+ "betterAuth": {
56
+ "errors": {
57
+ "emailInvalid": "Vui lòng nhập địa chỉ email hợp lệ",
58
+ "emailNotRegistered": "Email này chưa được đăng ký",
59
+ "emailNotVerified": "Email chưa được xác minh, vui lòng xác minh trước",
60
+ "emailRequired": "Vui lòng nhập địa chỉ email",
61
+ "firstNameRequired": "Vui lòng nhập tên",
62
+ "lastNameRequired": "Vui lòng nhập họ",
63
+ "loginFailed": "Đăng nhập thất bại, vui lòng kiểm tra email và mật khẩu",
64
+ "passwordFormat": "Mật khẩu phải bao gồm cả chữ và số",
65
+ "passwordMaxLength": "Mật khẩu không được vượt quá 64 ký tự",
66
+ "passwordMinLength": "Mật khẩu phải có ít nhất 8 ký tự",
67
+ "passwordRequired": "Vui lòng nhập mật khẩu",
68
+ "usernameRequired": "Vui lòng nhập tên người dùng"
69
+ },
70
+ "resetPassword": {
71
+ "backToSignIn": "Quay lại đăng nhập",
72
+ "confirmPasswordPlaceholder": "Xác nhận mật khẩu mới",
73
+ "confirmPasswordRequired": "Vui lòng xác nhận mật khẩu mới",
74
+ "description": "Vui lòng nhập mật khẩu mới của bạn",
75
+ "error": "Đặt lại mật khẩu thất bại, vui lòng thử lại",
76
+ "invalidToken": "Liên kết đặt lại không hợp lệ hoặc đã hết hạn",
77
+ "newPasswordPlaceholder": "Nhập mật khẩu mới",
78
+ "passwordMismatch": "Mật khẩu nhập lại không khớp",
79
+ "submit": "Đặt lại mật khẩu",
80
+ "success": "Đặt lại mật khẩu thành công, vui lòng đăng nhập bằng mật khẩu mới",
81
+ "title": "Đặt lại mật khẩu"
82
+ },
83
+ "signin": {
84
+ "backToEmail": "Quay lại chỉnh sửa email",
85
+ "continueWithAuth0": "Đăng nhập bằng Auth0",
86
+ "continueWithAuthelia": "Đăng nhập bằng Authelia",
87
+ "continueWithAuthentik": "Đăng nhập bằng Authentik",
88
+ "continueWithCasdoor": "Đăng nhập bằng Casdoor",
89
+ "continueWithCloudflareZeroTrust": "Đăng nhập bằng Cloudflare Zero Trust",
90
+ "continueWithCognito": "Đăng nhập bằng AWS Cognito",
91
+ "continueWithFeishu": "Đăng nhập bằng Feishu",
92
+ "continueWithGithub": "Đăng nhập bằng GitHub",
93
+ "continueWithGoogle": "Đăng nhập bằng Google",
94
+ "continueWithKeycloak": "Đăng nhập bằng Keycloak",
95
+ "continueWithLogto": "Đăng nhập bằng Logto",
96
+ "continueWithMicrosoft": "Đăng nhập bằng Microsoft",
97
+ "continueWithOIDC": "Đăng nhập bằng OIDC",
98
+ "continueWithOkta": "Đăng nhập bằng Okta",
99
+ "continueWithWechat": "Đăng nhập bằng WeChat",
100
+ "continueWithZitadel": "Đăng nhập bằng Zitadel",
101
+ "emailPlaceholder": "Vui lòng nhập địa chỉ email",
102
+ "emailStep": {
103
+ "subtitle": "Vui lòng nhập địa chỉ email của bạn để tiếp tục",
104
+ "title": "Đăng nhập"
105
+ },
106
+ "error": "Đăng nhập thất bại, vui lòng kiểm tra email và mật khẩu",
107
+ "forgotPassword": "Quên mật khẩu?",
108
+ "forgotPasswordError": "Gửi liên kết đặt lại mật khẩu thất bại",
109
+ "forgotPasswordSent": "Liên kết đặt lại mật khẩu đã được gửi, vui lòng kiểm tra email",
110
+ "magicLinkButton": "Gửi liên kết đăng nhập",
111
+ "magicLinkError": "Gửi liên kết đăng nhập thất bại, vui lòng thử lại sau",
112
+ "magicLinkSent": "Liên kết đăng nhập đã được gửi, vui lòng kiểm tra email",
113
+ "nextStep": "Bước tiếp theo",
114
+ "noAccount": "Chưa có tài khoản?",
115
+ "orContinueWith": "hoặc",
116
+ "passwordPlaceholder": "Vui lòng nhập mật khẩu",
117
+ "passwordStep": {
118
+ "subtitle": "Vui lòng nhập mật khẩu để tiếp tục"
119
+ },
120
+ "signupLink": "Đăng ký ngay",
121
+ "socialError": "Đăng nhập bằng mạng xã hội thất bại, vui lòng thử lại",
122
+ "socialOnlyHint": "Email này đã được đăng ký bằng tài khoản mạng xã hội, vui lòng đăng nhập bằng mạng xã hội",
123
+ "submit": "Đăng nhập"
124
+ },
125
+ "signup": {
126
+ "emailPlaceholder": "Vui lòng nhập địa chỉ email",
127
+ "error": "Đăng ký thất bại, vui lòng thử lại",
128
+ "firstNamePlaceholder": "Tên",
129
+ "hasAccount": "Đã có tài khoản?",
130
+ "lastNamePlaceholder": "Họ",
131
+ "passwordPlaceholder": "Vui lòng nhập mật khẩu",
132
+ "signinLink": "Đăng nhập ngay",
133
+ "submit": "Đăng ký",
134
+ "subtitle": "Tham gia cộng đồng LobeChat",
135
+ "success": "Đăng ký thành công! Vui lòng kiểm tra email để xác minh",
136
+ "title": "Tạo tài khoản",
137
+ "usernamePlaceholder": "Vui lòng nhập tên người dùng"
138
+ },
139
+ "verifyEmail": {
140
+ "backToSignIn": "Quay lại đăng nhập",
141
+ "checkSpam": "Nếu bạn không nhận được email, vui lòng kiểm tra thư mục spam",
142
+ "descriptionPrefix": "Chúng tôi đã gửi email xác minh đến",
143
+ "descriptionSuffix": "",
144
+ "resend": {
145
+ "button": "Gửi lại email xác minh",
146
+ "error": "Gửi thất bại, vui lòng thử lại sau",
147
+ "noEmail": "Thiếu địa chỉ email",
148
+ "success": "Email xác minh đã được gửi lại, vui lòng kiểm tra hộp thư"
149
+ },
150
+ "title": "Xác minh email của bạn"
151
+ }
152
+ },
55
153
  "date": {
56
154
  "prevMonth": "Tháng trước",
57
155
  "recent30Days": "30 ngày qua"
@@ -86,16 +184,31 @@
86
184
  "loginOrSignup": "Đăng nhập / Đăng ký",
87
185
  "profile": {
88
186
  "avatar": "Ảnh đại diện",
187
+ "cancel": "Hủy",
188
+ "changePassword": "Đặt lại mật khẩu",
89
189
  "email": "Địa chỉ email",
190
+ "fullName": "Họ và tên",
191
+ "fullNameInputHint": "Vui lòng nhập họ và tên mới",
192
+ "password": "Mật khẩu",
193
+ "resetPasswordError": "Gửi liên kết đặt lại mật khẩu thất bại",
194
+ "resetPasswordSent": "Liên kết đặt lại mật khẩu đã được gửi, vui lòng kiểm tra email",
195
+ "save": "Lưu",
90
196
  "sso": {
197
+ "link": {
198
+ "button": "Kết nối tài khoản",
199
+ "success": "Liên kết tài khoản thành công"
200
+ },
91
201
  "loading": "Đang tải tài khoản bên thứ ba đã liên kết",
92
202
  "providers": "Tài khoản liên kết",
93
203
  "unlink": {
94
- "description": "Sau khi hủy liên kết, bạn sẽ không thể sử dụng tài khoản {{provider}} {{providerAccountId}}” để đăng nhập. Nếu bạn cần liên kết lại tài khoản {{provider}} với tài khoản hiện tại, hãy đảm bảo rằng địa chỉ email của tài khoản {{provider}} là {{email}} , chúng tôi sẽ tự động liên kết nó với tài khoản đăng nhập hiện tại của bạn khi bạn đăng nhập.",
204
+ "description": "Sau khi hủy liên kết, bạn sẽ không thể đăng nhập bằng tài khoản {{provider}} \"{{providerAccountId}}\". Nếu bạn muốn liên kết lại tài khoản {{provider}} với tài khoản hiện tại, hãy đảm bảo địa chỉ email của tài khoản {{provider}} là {{email}}, chúng tôi sẽ tự động liên kết khi bạn đăng nhập.",
95
205
  "forbidden": "Bạn cần phải giữ lại ít nhất một tài khoản bên thứ ba được liên kết.",
96
206
  "title": "Có chắc chắn muốn hủy liên kết tài khoản bên thứ ba {{provider}}?"
97
207
  }
98
208
  },
209
+ "title": "Chi tiết hồ sơ cá nhân",
210
+ "updateAvatar": "Cập nhật ảnh đại diện",
211
+ "updateFullName": "Cập nhật họ và tên",
99
212
  "username": "Tên người dùng"
100
213
  },
101
214
  "signout": "Đăng xuất",
@@ -67,24 +67,37 @@
67
67
  "passwordRequired": "请输入密码",
68
68
  "usernameRequired": "请输入用户名"
69
69
  },
70
+ "resetPassword": {
71
+ "backToSignIn": "返回登录",
72
+ "confirmPasswordPlaceholder": "确认新密码",
73
+ "confirmPasswordRequired": "请确认新密码",
74
+ "description": "请输入您的新密码",
75
+ "error": "重置密码失败,请重试",
76
+ "invalidToken": "无效或已过期的重置链接",
77
+ "newPasswordPlaceholder": "输入新密码",
78
+ "passwordMismatch": "两次输入的密码不一致",
79
+ "submit": "重置密码",
80
+ "success": "密码重置成功,请使用新密码登录",
81
+ "title": "重置密码"
82
+ },
70
83
  "signin": {
71
84
  "backToEmail": "返回修改邮箱",
72
- "continueWithCognito": "使用 AWS Cognito 登录",
73
- "continueWithGithub": "使用 GitHub 登录",
74
- "continueWithGoogle": "使用 Google 登录",
75
- "continueWithMicrosoft": "使用 Microsoft 登录",
76
85
  "continueWithAuth0": "使用 Auth0 登录",
77
86
  "continueWithAuthelia": "使用 Authelia 登录",
78
87
  "continueWithAuthentik": "使用 Authentik 登录",
79
88
  "continueWithCasdoor": "使用 Casdoor 登录",
80
89
  "continueWithCloudflareZeroTrust": "使用 Cloudflare Zero Trust 登录",
81
- "continueWithOIDC": "使用 OIDC 登录",
90
+ "continueWithCognito": "使用 AWS Cognito 登录",
91
+ "continueWithFeishu": "使用飞书登录",
92
+ "continueWithGithub": "使用 GitHub 登录",
93
+ "continueWithGoogle": "使用 Google 登录",
82
94
  "continueWithKeycloak": "使用 Keycloak 登录",
83
95
  "continueWithLogto": "使用 Logto 登录",
96
+ "continueWithMicrosoft": "使用 Microsoft 登录",
97
+ "continueWithOIDC": "使用 OIDC 登录",
84
98
  "continueWithOkta": "使用 Okta 登录",
85
- "continueWithZitadel": "使用 Zitadel 登录",
86
- "continueWithFeishu": "使用飞书登录",
87
99
  "continueWithWechat": "使用微信登录",
100
+ "continueWithZitadel": "使用 Zitadel 登录",
88
101
  "emailPlaceholder": "请输入邮箱地址",
89
102
  "emailStep": {
90
103
  "subtitle": "请输入您的邮箱地址以继续",
@@ -94,6 +107,9 @@
94
107
  "forgotPassword": "忘记密码?",
95
108
  "forgotPasswordError": "发送重置密码链接失败",
96
109
  "forgotPasswordSent": "重置密码链接已发送,请检查邮箱",
110
+ "magicLinkButton": "发送登录链接",
111
+ "magicLinkError": "发送登录链接失败,请稍后再试",
112
+ "magicLinkSent": "登录链接已发送,请检查邮箱",
97
113
  "nextStep": "下一步",
98
114
  "noAccount": "还没有账号?",
99
115
  "orContinueWith": "或",
@@ -104,9 +120,6 @@
104
120
  "signupLink": "立即注册",
105
121
  "socialError": "社交登录失败,请重试",
106
122
  "socialOnlyHint": "该邮箱使用社交账号注册,请使用社交账号登录",
107
- "magicLinkButton": "发送登录链接",
108
- "magicLinkSent": "登录链接已发送,请检查邮箱",
109
- "magicLinkError": "发送登录链接失败,请稍后再试",
110
123
  "submit": "登录"
111
124
  },
112
125
  "signup": {
@@ -118,29 +131,23 @@
118
131
  "passwordPlaceholder": "请输入密码",
119
132
  "signinLink": "立即登录",
120
133
  "submit": "注册",
121
- "success": "注册成功!请检查您的邮箱验证邮件",
122
134
  "subtitle": "加入 LobeChat 社区",
135
+ "success": "注册成功!请检查您的邮箱验证邮件",
123
136
  "title": "创建账号",
124
137
  "usernamePlaceholder": "请输入用户名"
125
138
  },
126
139
  "verifyEmail": {
127
140
  "backToSignIn": "返回登录",
128
141
  "checkSpam": "如果没有收到邮件,请检查垃圾邮件文件夹",
129
- "description": "我们已向 {{email}} 发送了验证邮件",
142
+ "descriptionPrefix": "我们已向",
143
+ "descriptionSuffix": "发送了验证邮件",
144
+ "resend": {
145
+ "button": "重新发送验证邮件",
146
+ "error": "发送失败,请稍后重试",
147
+ "noEmail": "邮箱地址缺失",
148
+ "success": "验证邮件已重新发送,请检查您的邮箱"
149
+ },
130
150
  "title": "验证您的邮箱"
131
- },
132
- "resetPassword": {
133
- "backToSignIn": "返回登录",
134
- "confirmPasswordPlaceholder": "确认新密码",
135
- "confirmPasswordRequired": "请确认新密码",
136
- "description": "请输入您的新密码",
137
- "error": "重置密码失败,请重试",
138
- "invalidToken": "无效或已过期的重置链接",
139
- "newPasswordPlaceholder": "输入新密码",
140
- "passwordMismatch": "两次输入的密码不一致",
141
- "submit": "重置密码",
142
- "success": "密码重置成功,请使用新密码登录",
143
- "title": "重置密码"
144
151
  }
145
152
  },
146
153
  "date": {
@@ -186,9 +193,6 @@
186
193
  "resetPasswordError": "发送密码重置链接失败",
187
194
  "resetPasswordSent": "密码重置链接已发送,请检查邮箱",
188
195
  "save": "保存",
189
- "title": "个人资料详情",
190
- "updateAvatar": "更新头像",
191
- "updateFullName": "更新全名",
192
196
  "sso": {
193
197
  "link": {
194
198
  "button": "连接帐户",
@@ -197,11 +201,14 @@
197
201
  "loading": "正在加载已绑定的第三方账户",
198
202
  "providers": "连接的帐户",
199
203
  "unlink": {
200
- "description": "解绑后,您将无法使用 {{provider}} 账户 「{{providerAccountId}}登录。如果您需要重新绑定 {{provider}} 账户到当前账户,请确保 {{provider}} 账户的邮件地址为 {{email}} ,我们会在登陆时为你自动绑定到当前登录账户。",
204
+ "description": "解绑后,您将无法使用 {{provider}} 账户\"{{providerAccountId}}\"登录。如果您需要重新绑定 {{provider}} 账户到当前账户,请确保 {{provider}} 账户的邮件地址为 {{email}} ,我们会在登陆时为你自动绑定到当前登录账户。",
201
205
  "forbidden": "您至少需要保留一个第三方账户绑定。",
202
206
  "title": "是否解绑该第三方账户 {{provider}} ?"
203
207
  }
204
208
  },
209
+ "title": "个人资料详情",
210
+ "updateAvatar": "更新头像",
211
+ "updateFullName": "更新全名",
205
212
  "username": "用户名"
206
213
  },
207
214
  "signout": "退出登录",
@@ -52,6 +52,104 @@
52
52
  "required": "內容不得為空"
53
53
  }
54
54
  },
55
+ "betterAuth": {
56
+ "errors": {
57
+ "emailInvalid": "請輸入有效的電子郵件地址",
58
+ "emailNotRegistered": "該電子郵件尚未註冊",
59
+ "emailNotVerified": "電子郵件尚未驗證,請先完成驗證",
60
+ "emailRequired": "請輸入電子郵件地址",
61
+ "firstNameRequired": "請輸入名字",
62
+ "lastNameRequired": "請輸入姓氏",
63
+ "loginFailed": "登入失敗,請檢查電子郵件與密碼",
64
+ "passwordFormat": "密碼必須同時包含字母與數字",
65
+ "passwordMaxLength": "密碼長度不得超過 64 個字元",
66
+ "passwordMinLength": "密碼長度至少需為 8 個字元",
67
+ "passwordRequired": "請輸入密碼",
68
+ "usernameRequired": "請輸入使用者名稱"
69
+ },
70
+ "resetPassword": {
71
+ "backToSignIn": "返回登入",
72
+ "confirmPasswordPlaceholder": "確認新密碼",
73
+ "confirmPasswordRequired": "請確認新密碼",
74
+ "description": "請輸入您的新密碼",
75
+ "error": "重設密碼失敗,請重試",
76
+ "invalidToken": "無效或已過期的重設連結",
77
+ "newPasswordPlaceholder": "輸入新密碼",
78
+ "passwordMismatch": "兩次輸入的密碼不一致",
79
+ "submit": "重設密碼",
80
+ "success": "密碼重設成功,請使用新密碼登入",
81
+ "title": "重設密碼"
82
+ },
83
+ "signin": {
84
+ "backToEmail": "返回修改電子郵件",
85
+ "continueWithAuth0": "使用 Auth0 登入",
86
+ "continueWithAuthelia": "使用 Authelia 登入",
87
+ "continueWithAuthentik": "使用 Authentik 登入",
88
+ "continueWithCasdoor": "使用 Casdoor 登入",
89
+ "continueWithCloudflareZeroTrust": "使用 Cloudflare Zero Trust 登入",
90
+ "continueWithCognito": "使用 AWS Cognito 登入",
91
+ "continueWithFeishu": "使用飛書登入",
92
+ "continueWithGithub": "使用 GitHub 登入",
93
+ "continueWithGoogle": "使用 Google 登入",
94
+ "continueWithKeycloak": "使用 Keycloak 登入",
95
+ "continueWithLogto": "使用 Logto 登入",
96
+ "continueWithMicrosoft": "使用 Microsoft 登入",
97
+ "continueWithOIDC": "使用 OIDC 登入",
98
+ "continueWithOkta": "使用 Okta 登入",
99
+ "continueWithWechat": "使用微信登入",
100
+ "continueWithZitadel": "使用 Zitadel 登入",
101
+ "emailPlaceholder": "請輸入電子郵件地址",
102
+ "emailStep": {
103
+ "subtitle": "請輸入您的電子郵件地址以繼續",
104
+ "title": "登入"
105
+ },
106
+ "error": "登入失敗,請檢查電子郵件與密碼",
107
+ "forgotPassword": "忘記密碼?",
108
+ "forgotPasswordError": "發送重設密碼連結失敗",
109
+ "forgotPasswordSent": "重設密碼連結已發送,請查收電子郵件",
110
+ "magicLinkButton": "發送登入連結",
111
+ "magicLinkError": "發送登入連結失敗,請稍後再試",
112
+ "magicLinkSent": "登入連結已發送,請查收電子郵件",
113
+ "nextStep": "下一步",
114
+ "noAccount": "還沒有帳號?",
115
+ "orContinueWith": "或",
116
+ "passwordPlaceholder": "請輸入密碼",
117
+ "passwordStep": {
118
+ "subtitle": "請輸入密碼以繼續"
119
+ },
120
+ "signupLink": "立即註冊",
121
+ "socialError": "社交登入失敗,請重試",
122
+ "socialOnlyHint": "該電子郵件使用社交帳號註冊,請使用社交帳號登入",
123
+ "submit": "登入"
124
+ },
125
+ "signup": {
126
+ "emailPlaceholder": "請輸入電子郵件地址",
127
+ "error": "註冊失敗,請重試",
128
+ "firstNamePlaceholder": "名字",
129
+ "hasAccount": "已有帳號?",
130
+ "lastNamePlaceholder": "姓氏",
131
+ "passwordPlaceholder": "請輸入密碼",
132
+ "signinLink": "立即登入",
133
+ "submit": "註冊",
134
+ "subtitle": "加入 LobeChat 社群",
135
+ "success": "註冊成功!請查收您的電子郵件驗證信",
136
+ "title": "建立帳號",
137
+ "usernamePlaceholder": "請輸入使用者名稱"
138
+ },
139
+ "verifyEmail": {
140
+ "backToSignIn": "返回登入",
141
+ "checkSpam": "如果沒有收到郵件,請檢查垃圾郵件資料夾",
142
+ "descriptionPrefix": "我們已向",
143
+ "descriptionSuffix": "發送了驗證郵件",
144
+ "resend": {
145
+ "button": "重新發送驗證郵件",
146
+ "error": "發送失敗,請稍後再試",
147
+ "noEmail": "缺少電子郵件地址",
148
+ "success": "驗證郵件已重新發送,請查收您的電子郵件"
149
+ },
150
+ "title": "驗證您的電子郵件"
151
+ }
152
+ },
55
153
  "date": {
56
154
  "prevMonth": "上個月",
57
155
  "recent30Days": "最近30天"
@@ -86,16 +184,31 @@
86
184
  "loginOrSignup": "登入 / 註冊",
87
185
  "profile": {
88
186
  "avatar": "頭像",
187
+ "cancel": "取消",
188
+ "changePassword": "重設密碼",
89
189
  "email": "電子郵件地址",
190
+ "fullName": "全名",
191
+ "fullNameInputHint": "請輸入新的全名",
192
+ "password": "密碼",
193
+ "resetPasswordError": "發送密碼重設連結失敗",
194
+ "resetPasswordSent": "密碼重設連結已發送,請查收電子郵件",
195
+ "save": "儲存",
90
196
  "sso": {
197
+ "link": {
198
+ "button": "連接帳號",
199
+ "success": "帳號連接成功"
200
+ },
91
201
  "loading": "正在載入已綁定的第三方帳戶",
92
202
  "providers": "連結的帳戶",
93
203
  "unlink": {
94
- "description": "解除綁定後,您將無法使用 {{provider}} 帳戶「{{providerAccountId}}」登入。如果您需要重新綁定 {{provider}} 帳戶到當前帳戶,請確保 {{provider}} 帳戶的電子郵件地址為 {{email}},我們會在登入時為您自動綁定到當前登入帳戶。",
204
+ "description": "解除連結後,您將無法使用 {{provider}} 帳號「{{providerAccountId}}」登入。若您需要重新將 {{provider}} 帳號綁定至目前帳號,請確保 {{provider}} 帳號的電子郵件地址為 {{email}},我們將在登入時自動為您綁定至目前登入帳號。",
95
205
  "forbidden": "您至少需要保留一個第三方帳戶綁定。",
96
206
  "title": "是否解除綁定該第三方帳戶 {{provider}} ?"
97
207
  }
98
208
  },
209
+ "title": "個人資料詳情",
210
+ "updateAvatar": "更新頭像",
211
+ "updateFullName": "更新全名",
99
212
  "username": "用戶名"
100
213
  },
101
214
  "signout": "登出",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.127",
3
+ "version": "2.0.0-next.128",
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",
@@ -189,6 +189,7 @@
189
189
  "@trpc/next": "^11.7.1",
190
190
  "@trpc/react-query": "^11.7.1",
191
191
  "@trpc/server": "^11.7.1",
192
+ "@upstash/redis": "^1.35.7",
192
193
  "@vercel/analytics": "^1.5.0",
193
194
  "@vercel/edge-config": "^1.4.3",
194
195
  "@vercel/functions": "^3.3.2",
@@ -222,6 +223,7 @@
222
223
  "i18next-browser-languagedetector": "^8.2.0",
223
224
  "i18next-resources-to-backend": "^1.2.1",
224
225
  "immer": "^10.2.0",
226
+ "ioredis": "^5.4.1",
225
227
  "jose": "^5.10.0",
226
228
  "js-sha256": "^0.11.1",
227
229
  "jsonl-parse-stringify": "^1.0.3",
@@ -331,6 +333,7 @@
331
333
  "@types/crypto-js": "^4.2.2",
332
334
  "@types/debug": "^4.1.12",
333
335
  "@types/fs-extra": "^11.0.4",
336
+ "@types/ioredis": "^5.0.0",
334
337
  "@types/ip": "^1.1.3",
335
338
  "@types/json-schema": "^7.0.15",
336
339
  "@types/lodash": "^4.17.20",
@@ -207,7 +207,7 @@ export class DatabaseManager {
207
207
  return this.db;
208
208
  }
209
209
 
210
- // 初始化数据库
210
+ // Initialize database
211
211
  async initialize(callbacks?: DatabaseLoadingCallbacks): Promise<DrizzleInstance> {
212
212
  if (this.initPromise) return this.initPromise;
213
213
 
@@ -218,13 +218,13 @@ export class DatabaseManager {
218
218
  if (this.dbInstance) return this.dbInstance;
219
219
 
220
220
  const time = Date.now();
221
- // 初始化数据库
221
+ // Initialize database
222
222
  this.callbacks?.onStateChange?.(DatabaseLoadingState.Initializing);
223
223
 
224
- // 加载依赖
224
+ // Load dependencies
225
225
  const { fsBundle, PGlite, MemoryFS, IdbFs, vector } = await this.loadDependencies();
226
226
 
227
- // 加载并编译 WASM 模块
227
+ // Load and compile WASM module
228
228
  const wasmModule = await this.loadWasmModule();
229
229
 
230
230
  const { initPgliteWorker } = await import('./pglite');
@@ -267,10 +267,10 @@ export class DatabaseManager {
267
267
  this.callbacks?.onStateChange?.(DatabaseLoadingState.Error);
268
268
  const error = e as Error;
269
269
 
270
- // 查询迁移表数据
270
+ // Query migration table data
271
271
  let migrationsTableData: MigrationTableItem[] = [];
272
272
  try {
273
- // 尝试查询迁移表
273
+ // Attempt to query migration table
274
274
  const drizzleMigration = new DrizzleMigrationModel(this.db as any);
275
275
  migrationsTableData = await drizzleMigration.getMigrationList();
276
276
  } catch (queryError) {
@@ -295,7 +295,7 @@ export class DatabaseManager {
295
295
  return this.initPromise;
296
296
  }
297
297
 
298
- // 获取数据库实例
298
+ // Get database instance
299
299
  get db(): DrizzleInstance {
300
300
  if (!this.dbInstance) {
301
301
  throw new Error('Database not initialized. Please call initialize() first.');
@@ -303,7 +303,7 @@ export class DatabaseManager {
303
303
  return this.dbInstance;
304
304
  }
305
305
 
306
- // 创建代理对象
306
+ // Create proxy object
307
307
  createProxy(): DrizzleInstance {
308
308
  return new Proxy({} as DrizzleInstance, {
309
309
  get: (target, prop) => {
@@ -313,7 +313,7 @@ export class DatabaseManager {
313
313
  }
314
314
 
315
315
  async resetDatabase(): Promise<void> {
316
- // 1. 关闭现有的 PGlite 连接(如果存在)
316
+ // 1. Close existing PGlite connection (if exists)
317
317
  if (this.dbInstance) {
318
318
  try {
319
319
  // @ts-ignore
@@ -321,31 +321,31 @@ export class DatabaseManager {
321
321
  console.log('PGlite instance closed successfully.');
322
322
  } catch (e) {
323
323
  console.error('Error closing PGlite instance:', e);
324
- // 即使关闭失败,也尝试继续删除,IndexedDB onblocked onerror 会处理后续问题
324
+ // Even if closing fails, continue with deletion attempt; IndexedDB onblocked or onerror will handle subsequent issues
325
325
  }
326
326
  }
327
327
 
328
- // 2. 重置数据库实例和初始化状态
328
+ // 2. Reset database instance and initialization state
329
329
  this.dbInstance = null;
330
330
  this.initPromise = null;
331
- this.isLocalDBSchemaSynced = false; // 重置同步状态
331
+ this.isLocalDBSchemaSynced = false; // Reset sync state
332
332
 
333
- // 3. 删除 IndexedDB 数据库
333
+ // 3. Delete IndexedDB database
334
334
  return new Promise<void>((resolve, reject) => {
335
- // 检查 IndexedDB 是否可用
335
+ // Check if IndexedDB is available
336
336
  if (typeof indexedDB === 'undefined') {
337
337
  console.warn('IndexedDB is not available, cannot delete database');
338
- resolve(); // 在此环境下无法删除,直接解决
338
+ resolve(); // Cannot delete in this environment, resolve directly
339
339
  return;
340
340
  }
341
341
 
342
- const dbName = `/pglite/${DB_NAME}`; // PGlite IdbFs 使用的路径
342
+ const dbName = `/pglite/${DB_NAME}`; // Path used by PGlite IdbFs
343
343
  const request = indexedDB.deleteDatabase(dbName);
344
344
 
345
345
  request.onsuccess = () => {
346
346
  console.log(`✅ Database '${dbName}' reset successfully`);
347
347
 
348
- // 清除本地存储的模式哈希
348
+ // Clear locally stored schema hash
349
349
  if (typeof localStorage !== 'undefined') {
350
350
  localStorage.removeItem(pgliteSchemaHashCache);
351
351
  }
@@ -365,7 +365,7 @@ export class DatabaseManager {
365
365
  };
366
366
 
367
367
  request.onblocked = (event) => {
368
- // 当其他打开的连接阻止数据库删除时,会触发此事件
368
+ // This event is triggered when other open connections block database deletion
369
369
  console.warn(
370
370
  `Deletion of database '${dbName}' is blocked. This usually means other connections (e.g., in other tabs) are still open. Event:`,
371
371
  event,
@@ -380,13 +380,13 @@ export class DatabaseManager {
380
380
  }
381
381
  }
382
382
 
383
- // 导出单例
383
+ // Export singleton
384
384
  const dbManager = DatabaseManager.getInstance();
385
385
 
386
- // 保持原有的 clientDB 导出不变
386
+ // Keep original clientDB export unchanged
387
387
  export const clientDB = dbManager.createProxy();
388
388
 
389
- // 导出初始化方法,供应用启动时使用
389
+ // Export initialization method for application startup
390
390
  export const initializeDB = (callbacks?: DatabaseLoadingCallbacks) =>
391
391
  dbManager.initialize(callbacks);
392
392
 
@@ -127,7 +127,7 @@ export class DeprecatedDataImporterRepos {
127
127
  // filter out existing session, only insert new ones
128
128
  .filter((s) => query.every((q) => q.clientId !== s.id));
129
129
 
130
- // 只有当需要有新的 session 时,才会插入 agent
130
+ // Only insert agent when new sessions are needed
131
131
  if (shouldInsertSessionAgents.length > 0) {
132
132
  const agentMapArray = await trx
133
133
  .insert(agents)
@@ -221,14 +221,14 @@ export class DeprecatedDataImporterRepos {
221
221
  parentId: null,
222
222
  provider: extra?.fromProvider,
223
223
  sessionId: sessionId ? sessionIdMap[sessionId] : null,
224
- topicId: topicId ? topicIdMap[topicId] : null, // 暂时设为 NULL
224
+ topicId: topicId ? topicIdMap[topicId] : null, // Temporarily set to NULL
225
225
  updatedAt: new Date(updatedAt),
226
226
  userId: this.userId,
227
227
  }),
228
228
  );
229
229
 
230
230
  console.time('insert messages');
231
- const BATCH_SIZE = 100; // 每批次插入的记录数
231
+ const BATCH_SIZE = 100; // Number of records to insert per batch
232
232
 
233
233
  for (let i = 0; i < inertValues.length; i += BATCH_SIZE) {
234
234
  const batch = inertValues.slice(i, i + BATCH_SIZE);
@@ -257,7 +257,7 @@ export class DeprecatedDataImporterRepos {
257
257
  // 3. update parentId for messages
258
258
  console.time('execute updates parentId');
259
259
  const parentIdUpdates = shouldInsertMessages
260
- .filter((msg) => msg.parentId) // 只处理有 parentId 的消息
260
+ .filter((msg) => msg.parentId) // Only process messages with parentId
261
261
  .map((msg) => {
262
262
  if (messageIdMap[msg.parentId as string])
263
263
  return sql`WHEN ${messages.clientId} = ${msg.id} THEN ${messageIdMap[msg.parentId as string]} `;
@@ -315,7 +315,7 @@ export class DeprecatedDataImporterRepos {
315
315
  );
316
316
  }
317
317
 
318
- // TODO: 未来需要处理 TTS 和图片的插入 (目前存在 file 的部分,不方便处理)
318
+ // TODO: Need to handle TTS and image insertion in the future (currently difficult to handle due to file-related parts)
319
319
  }
320
320
 
321
321
  messageResult.added = shouldInsertMessages.length;