@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.
- package/.env.example +23 -3
- package/.env.example.development +5 -0
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/docker-compose/local/docker-compose.yml +24 -1
- package/docker-compose/local/logto/docker-compose.yml +25 -2
- package/docker-compose.development.yml +6 -0
- package/locales/ar/auth.json +114 -1
- package/locales/bg-BG/auth.json +114 -1
- package/locales/de-DE/auth.json +114 -1
- package/locales/en-US/auth.json +42 -22
- package/locales/es-ES/auth.json +114 -1
- package/locales/fa-IR/auth.json +114 -1
- package/locales/fr-FR/auth.json +114 -1
- package/locales/it-IT/auth.json +114 -1
- package/locales/ja-JP/auth.json +114 -1
- package/locales/ko-KR/auth.json +114 -1
- package/locales/nl-NL/auth.json +114 -1
- package/locales/pl-PL/auth.json +114 -1
- package/locales/pt-BR/auth.json +114 -1
- package/locales/ru-RU/auth.json +114 -1
- package/locales/tr-TR/auth.json +114 -1
- package/locales/vi-VN/auth.json +114 -1
- package/locales/zh-CN/auth.json +36 -29
- package/locales/zh-TW/auth.json +114 -1
- package/package.json +4 -1
- package/packages/database/src/client/db.ts +21 -21
- package/packages/database/src/repositories/dataImporter/deprecated/index.ts +5 -5
- package/packages/database/src/repositories/dataImporter/index.ts +59 -59
- package/packages/database/src/schemas/generation.ts +16 -16
- package/packages/database/src/schemas/oidc.ts +36 -36
- package/packages/model-runtime/src/providers/newapi/index.ts +61 -18
- package/packages/model-runtime/src/runtimeMap.ts +1 -0
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/UpdateProviderInfo/SettingModal.tsx +10 -6
- package/src/envs/redis.ts +106 -0
- package/src/libs/redis/index.ts +5 -0
- package/src/libs/redis/manager.test.ts +107 -0
- package/src/libs/redis/manager.ts +56 -0
- package/src/libs/redis/redis.test.ts +158 -0
- package/src/libs/redis/redis.ts +117 -0
- package/src/libs/redis/types.ts +71 -0
- package/src/libs/redis/upstash.test.ts +154 -0
- package/src/libs/redis/upstash.ts +109 -0
- package/src/libs/redis/utils.test.ts +46 -0
- package/src/libs/redis/utils.ts +53 -0
- package/.github/workflows/check-console-log.yml +0 -117
package/locales/vi-VN/auth.json
CHANGED
|
@@ -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ể
|
|
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",
|
package/locales/zh-CN/auth.json
CHANGED
|
@@ -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
|
-
"
|
|
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
|
-
"
|
|
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}}
|
|
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": "退出登录",
|
package/locales/zh-TW/auth.json
CHANGED
|
@@ -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": "
|
|
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.
|
|
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
|
-
//
|
|
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.
|
|
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
|
-
//
|
|
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.
|
|
333
|
+
// 3. Delete IndexedDB database
|
|
334
334
|
return new Promise<void>((resolve, reject) => {
|
|
335
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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, //
|
|
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) //
|
|
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:
|
|
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;
|