From 30a49ae6115b9c35bdf9a248e07f22971185dccf Mon Sep 17 00:00:00 2001 From: Dan Orlando Date: Mon, 31 Jul 2023 19:37:46 -0700 Subject: [PATCH] Feat email password reset (#730) * change name of auth.service to AuthService * Add emailEnabled to config api * Setup email * update nodemailer version * add translations * update .env.example * clean up console.log's) * refactor RequestPasswordReset component * chore: rebuild package-lock.json --------- Co-authored-by: Daniel Avila --- .env.example | 10 ++ api/package.json | 2 +- api/server/controllers/AuthController.js | 8 +- .../controllers/auth/LogoutController.js | 2 +- api/server/routes/config.js | 6 + .../{auth.service.js => AuthService.js} | 32 ++-- api/utils/sendEmail.js | 27 +-- .../components/Auth/RequestPasswordReset.tsx | 170 ++++++++++-------- client/src/localization/languages/Br.tsx | 3 + client/src/localization/languages/Eng.tsx | 3 + client/src/localization/languages/Es.tsx | 2 + client/src/localization/languages/It.tsx | 3 + client/src/localization/languages/Zh.tsx | 2 + package-lock.json | 118 ++++++------ packages/data-provider/src/types.ts | 4 +- 15 files changed, 221 insertions(+), 171 deletions(-) rename api/server/services/{auth.service.js => AuthService.js} (90%) diff --git a/.env.example b/.env.example index 5855890dd1..251ddfb8a0 100644 --- a/.env.example +++ b/.env.example @@ -261,3 +261,13 @@ DISCORD_CALLBACK_URL=/oauth/discord/callback # this should be the same for every DOMAIN_CLIENT=http://localhost:3080 DOMAIN_SERVER=http://localhost:3080 + +########################### +# Email +########################### + +# Email is used for password reset. Note that all 4 values must be set for email to work. +EMAIL_SERVICE= # eg. gmail +EMAIL_USERNAME= # eg. your email address if using gmail +EMAIL_PASSWORD= # eg. this is the "app password" if using gmail +EMAIL_FROM= # eg. email address for from field like noreply@librechat.ai diff --git a/api/package.json b/api/package.json index 774bdd77f5..4cc5572f07 100644 --- a/api/package.json +++ b/api/package.json @@ -47,7 +47,7 @@ "lodash": "^4.17.21", "meilisearch": "^0.33.0", "mongoose": "^7.1.1", - "nodemailer": "^6.9.1", + "nodemailer": "^6.9.4", "openai": "^3.2.1", "openid-client": "^5.4.2", "passport": "^0.6.0", diff --git a/api/server/controllers/AuthController.js b/api/server/controllers/AuthController.js index 34631e7442..bedf827bac 100644 --- a/api/server/controllers/AuthController.js +++ b/api/server/controllers/AuthController.js @@ -1,4 +1,4 @@ -const { registerUser, requestPasswordReset, resetPassword } = require('../services/auth.service'); +const { registerUser, requestPasswordReset, resetPassword } = require('../services/AuthService'); const isProduction = process.env.NODE_ENV === 'production'; @@ -32,10 +32,10 @@ const getUserController = async (req, res) => { const resetPasswordRequestController = async (req, res) => { try { const resetService = await requestPasswordReset(req.body.email); - if (resetService.link) { - return res.status(200).json(resetService); - } else { + if (resetService instanceof Error) { return res.status(400).json(resetService); + } else { + return res.status(200).json(resetService); } } catch (e) { console.log(e); diff --git a/api/server/controllers/auth/LogoutController.js b/api/server/controllers/auth/LogoutController.js index 29bc70b7b0..227ff6ad21 100644 --- a/api/server/controllers/auth/LogoutController.js +++ b/api/server/controllers/auth/LogoutController.js @@ -1,4 +1,4 @@ -const { logoutUser } = require('../../services/auth.service'); +const { logoutUser } = require('../../services/AuthService'); const logoutController = async (req, res) => { const { signedCookies = {} } = req; diff --git a/api/server/routes/config.js b/api/server/routes/config.js index cf1611db3a..e52bda2e95 100644 --- a/api/server/routes/config.js +++ b/api/server/routes/config.js @@ -18,6 +18,11 @@ router.get('/', async function (req, res) { const serverDomain = process.env.DOMAIN_SERVER || 'http://localhost:3080'; const registrationEnabled = process.env.ALLOW_REGISTRATION === 'true'; const socialLoginEnabled = process.env.ALLOW_SOCIAL_LOGIN === 'true'; + const emailEnabled = + !!process.env.EMAIL_SERVICE && + !!process.env.EMAIL_USERNAME && + !!process.env.EMAIL_PASSWORD && + !!process.env.EMAIL_FROM; return res.status(200).send({ appTitle, @@ -30,6 +35,7 @@ router.get('/', async function (req, res) { serverDomain, registrationEnabled, socialLoginEnabled, + emailEnabled, }); } catch (err) { console.error(err); diff --git a/api/server/services/auth.service.js b/api/server/services/AuthService.js similarity index 90% rename from api/server/services/auth.service.js rename to api/server/services/AuthService.js index 8e321f918a..309a15a2ba 100644 --- a/api/server/services/auth.service.js +++ b/api/server/services/AuthService.js @@ -125,16 +125,26 @@ const requestPasswordReset = async (email) => { const link = `${domains.client}/reset-password?token=${resetToken}&userId=${user._id}`; - sendEmail( - user.email, - 'Password Reset Request', - { - name: user.name, - link: link, - }, - './template/requestResetPassword.handlebars', - ); - return { link }; + const emailEnabled = + !!process.env.EMAIL_SERVICE && + !!process.env.EMAIL_USERNAME && + !!process.env.EMAIL_PASSWORD && + !!process.env.EMAIL_FROM; + + if (emailEnabled) { + sendEmail( + user.email, + 'Password Reset Request', + { + name: user.name, + link: link, + }, + 'requestPasswordReset.handlebars', + ); + return { link: '' }; + } else { + return { link }; + } }; /** @@ -170,7 +180,7 @@ const resetPassword = async (userId, token, password) => { { name: user.name, }, - './template/resetPassword.handlebars', + 'resetPassword.handlebars', ); await passwordResetToken.deleteOne(); diff --git a/api/utils/sendEmail.js b/api/utils/sendEmail.js index cb9b3d0ff2..62b05c92c9 100644 --- a/api/utils/sendEmail.js +++ b/api/utils/sendEmail.js @@ -1,5 +1,3 @@ -/* eslint-disable no-unused-vars */ -/* eslint-disable no-undef */ const nodemailer = require('nodemailer'); const handlebars = require('handlebars'); const fs = require('fs'); @@ -7,21 +5,19 @@ const path = require('path'); const sendEmail = async (email, subject, payload, template) => { try { - // create reusable transporter object using the default SMTP transport const transporter = nodemailer.createTransport({ - host: process.env.EMAIL_HOST, - port: 465, + service: process.env.EMAIL_SERVICE, auth: { user: process.env.EMAIL_USERNAME, pass: process.env.EMAIL_PASSWORD, }, }); - const source = fs.readFileSync(path.join(__dirname, template), 'utf8'); + const source = fs.readFileSync(path.join(__dirname, 'emails', template), 'utf8'); const compiledTemplate = handlebars.compile(source); const options = () => { return { - from: process.env.FROM_EMAIL, + from: process.env.EMAIL_FROM, to: email, subject: subject, html: compiledTemplate(payload), @@ -31,26 +27,17 @@ const sendEmail = async (email, subject, payload, template) => { // Send email transporter.sendMail(options(), (error, info) => { if (error) { + console.log(error); return error; } else { - return res.status(200).json({ - success: true, - }); + console.log(info); + return info; } }); } catch (error) { + console.log(error); return error; } }; -/* -Example: -sendEmail( - "youremail@gmail.com, - "Email subject", - { name: "Eze" }, - "./templates/layouts/main.handlebars" -); -*/ - module.exports = sendEmail; diff --git a/client/src/components/Auth/RequestPasswordReset.tsx b/client/src/components/Auth/RequestPasswordReset.tsx index ec952d91ed..a465117114 100644 --- a/client/src/components/Auth/RequestPasswordReset.tsx +++ b/client/src/components/Auth/RequestPasswordReset.tsx @@ -1,10 +1,11 @@ -import { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { useRecoilValue } from 'recoil'; import store from '~/store'; import { localize } from '~/localization/Translation'; import { useRequestPasswordResetMutation, + useGetStartupConfig, TRequestPasswordReset, TRequestPasswordResetResponse, } from 'librechat-data-provider'; @@ -17,15 +18,19 @@ function RequestPasswordReset() { formState: { errors }, } = useForm(); const requestPasswordReset = useRequestPasswordResetMutation(); - const [success, setSuccess] = useState(false); + const config = useGetStartupConfig(); const [requestError, setRequestError] = useState(false); - const [resetLink, setResetLink] = useState(''); + const [resetLink, setResetLink] = useState(undefined); + const [headerText, setHeaderText] = useState(''); + const [bodyText, setBodyText] = useState(undefined); const onSubmit = (data: TRequestPasswordReset) => { requestPasswordReset.mutate(data, { onSuccess: (data: TRequestPasswordResetResponse) => { - setSuccess(true); - setResetLink(data.link); + console.log('emailEnabled: ', config.data?.emailEnabled); + if (!config.data?.emailEnabled) { + setResetLink(data.link); + } }, onError: () => { setRequestError(true); @@ -36,25 +41,33 @@ function RequestPasswordReset() { }); }; - return ( -
-
-

- {localize(lang, 'com_auth_reset_password')} -

- {success && ( -
+ useEffect(() => { + if (requestPasswordReset.isSuccess) { + if (config.data?.emailEnabled) { + setHeaderText(localize(lang, 'com_auth_reset_password_link_sent')); + setBodyText(localize(lang, 'com_auth_reset_password_email_sent')); + } else { + setHeaderText(localize(lang, 'com_auth_reset_password')); + setBodyText( + {localize(lang, 'com_auth_click')}{' '} {localize(lang, 'com_auth_here')} {' '} {localize(lang, 'com_auth_to_reset_your_password')} - {/* An email has been sent with instructions on how to reset your password. */} -
- )} + , + ); + } + } else { + setHeaderText(localize(lang, 'com_auth_reset_password')); + setBodyText(undefined); + } + }, [requestPasswordReset.isSuccess, config.data?.emailEnabled, resetLink, lang]); + + return ( +
+
+

{headerText}

{requestError && (
)} -
-
-
- - + {bodyText ? ( +
+ {bodyText} +
+ ) : ( + +
+
+ + +
+ {errors.email && ( + + {/* @ts-ignore not sure why */} + {errors.email.message} + + )}
- {errors.email && ( - - {/* @ts-ignore not sure why */} - {errors.email.message} - - )} -
-
- -
- +
+ +
+ + )}
); diff --git a/client/src/localization/languages/Br.tsx b/client/src/localization/languages/Br.tsx index febb33f7c7..dc46b41a33 100644 --- a/client/src/localization/languages/Br.tsx +++ b/client/src/localization/languages/Br.tsx @@ -52,6 +52,9 @@ export default { com_auth_password_forgot: 'Esqueceu a senha?', com_auth_password_confirm: 'Confirmar senha', com_auth_password_not_match: 'As senhas não correspondem', + com_auth_reset_password_link_sent: 'Link para redefinir a senha enviado', + com_auth_reset_password_email_sent: + 'Um email foi enviado para com instruções para redefinir sua senha.', com_auth_continue: 'Continuar', com_auth_create_account: 'Crie sua conta', com_auth_error_create: diff --git a/client/src/localization/languages/Eng.tsx b/client/src/localization/languages/Eng.tsx index 51df41dbb8..9979eabb37 100644 --- a/client/src/localization/languages/Eng.tsx +++ b/client/src/localization/languages/Eng.tsx @@ -69,6 +69,9 @@ export default { com_auth_click: 'Click', com_auth_here: 'HERE', com_auth_to_reset_your_password: 'to reset your password.', + com_auth_reset_password_link_sent: 'Email Sent', + com_auth_reset_password_email_sent: + 'An email has been sent to you with further instructions to reset your password.', com_auth_error_reset_password: 'There was a problem resetting your password. There was no user found with the email address provided. Please try again.', com_auth_reset_password_success: 'Password Reset Success', diff --git a/client/src/localization/languages/Es.tsx b/client/src/localization/languages/Es.tsx index 3e65d9e3ae..d748d1ee18 100644 --- a/client/src/localization/languages/Es.tsx +++ b/client/src/localization/languages/Es.tsx @@ -46,6 +46,8 @@ export default { com_auth_email_max_length: 'El email no debe tener más de 120 caracteres', com_auth_email_pattern: 'Debes ingresar una dirección de email válida', com_auth_email_address: 'Dirección de email', + com_auth_reset_password_link_sent: 'Enlace para restablecer la contraseña enviado', + com_auth_reset_password_email_sent: 'Se ha enviado un correo electrónico con instrucciones.', com_auth_password: 'Contraseña', com_auth_password_required: 'Se requiere la contraseña', com_auth_password_min_length: 'La contraseña debe tener al menos 8 caracteres', diff --git a/client/src/localization/languages/It.tsx b/client/src/localization/languages/It.tsx index 86e2b6c293..22312953b5 100644 --- a/client/src/localization/languages/It.tsx +++ b/client/src/localization/languages/It.tsx @@ -52,6 +52,9 @@ export default { com_auth_password_forgot: 'Password dimenticata?', com_auth_password_confirm: 'Conferma password', com_auth_password_not_match: 'Le password non corrispondono', + com_auth_reset_password_link_sent: 'Link per reimpostare la password inviato', + com_auth_reset_password_email_sent: + 'Ti abbiamo inviato un\'email con un link per reimpostare la password.', com_auth_continue: 'Continua', com_auth_create_account: 'Crea il tuo account', com_auth_error_create: diff --git a/client/src/localization/languages/Zh.tsx b/client/src/localization/languages/Zh.tsx index 73a18e5294..01f790631f 100644 --- a/client/src/localization/languages/Zh.tsx +++ b/client/src/localization/languages/Zh.tsx @@ -52,6 +52,8 @@ export default { com_auth_continue: '继续', com_auth_create_account: '创建账号', com_auth_error_create: '注册账户过程中出现错误,请重试。', + com_auth_reset_password_link_sent: '重置密码链接已发送至邮箱', + com_auth_reset_password_email_sent: '重置密码邮件已发送至邮箱', com_auth_full_name: '姓名', com_auth_name_required: '姓名为必填项', com_auth_name_min_length: '姓名至少3个字符', diff --git a/package-lock.json b/package-lock.json index 97b5c78d31..a3a854606e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,7 @@ "lodash": "^4.17.21", "meilisearch": "^0.33.0", "mongoose": "^7.1.1", - "nodemailer": "^6.9.1", + "nodemailer": "^6.9.4", "openai": "^3.2.1", "openid-client": "^5.4.2", "passport": "^0.6.0", @@ -243,9 +243,9 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.5.8.tgz", - "integrity": "sha512-iHenjcE2Q/az6VZiP1DueOSvKNRmxsly6Rx2yjJBoy7OBYVFGVjEdgs2mPQHtTX0ibKAR7tPq6F6MQbKDPWcKg==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.5.9.tgz", + "integrity": "sha512-9/TYca4qSe0xG40LLNf5vemybw5JAKF5OE6Eiyc+O+h3+VGGPeOKo+1SHaWBP5zS7bGX2o3Ne6EonPWyh9oNqA==", "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -7472,9 +7472,9 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/react": { - "version": "18.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.17.tgz", - "integrity": "sha512-u+e7OlgPPh+aryjOm5UJMX32OvB2E3QASOAqVMY6Ahs90djagxwv2ya0IctglNbNTexC12qCSMZG47KPfy1hAA==", + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.18.tgz", + "integrity": "sha512-da4NTSeBv/P34xoZPhtcLkmZuJ+oYaCxHmyHzwaDQo9RQPBeXV+06gEk2FpqEcsX9XrnNLvRpVh6bdavDSjtiQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -7761,12 +7761,12 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.3.tgz", - "integrity": "sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz", + "integrity": "sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==", "dev": true, "dependencies": { - "@babel/core": "^7.22.5", + "@babel/core": "^7.22.9", "@babel/plugin-transform-react-jsx-self": "^7.22.5", "@babel/plugin-transform-react-jsx-source": "^7.22.5", "react-refresh": "^0.14.0" @@ -9485,9 +9485,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "funding": [ { @@ -9504,9 +9504,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.11" }, "bin": { @@ -9704,9 +9704,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001517", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz", - "integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==", + "version": "1.0.30001518", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001518.tgz", + "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", "dev": true, "funding": [ { @@ -10776,9 +10776,9 @@ } }, "node_modules/dedent": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.3.0.tgz", - "integrity": "sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -11177,9 +11177,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.477", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.477.tgz", - "integrity": "sha512-shUVy6Eawp33dFBFIoYbIwLHrX0IZ857AlH9ug2o4rvbWmpaCUdBpQ5Zw39HRrfzAFm4APJE9V+E2A/WB0YqJw==", + "version": "1.4.478", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.478.tgz", + "integrity": "sha512-qjTA8djMXd+ruoODDFGnRCRBpID+AAfYWCyGtYTNhsuwxI19s8q19gbjKTwRS5z/LyVf5wICaIiPQGLekmbJbA==", "dev": true }, "node_modules/elliptic": { @@ -17274,9 +17274,9 @@ } }, "node_modules/langsmith": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.0.15.tgz", - "integrity": "sha512-SVLJEm94aK9mmqE3z2wlpzLjPNodnPJHp1MZdmXG2ysUWSFsRVuGkd6A/GTzlEZ6OofyJSOg6tcNFJSFOi13QQ==", + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.0.16.tgz", + "integrity": "sha512-HD97KJaSpCcuixbjfRhpSFdo5rWz28OJiUVs5uBRZDKUN2Amg4PWd0NFzGO3xC8osnjPPRvgH9by6Ige79hjxQ==", "dependencies": { "@types/uuid": "^9.0.1", "commander": "^10.0.1", @@ -26550,7 +26550,7 @@ }, "packages/data-provider": { "name": "librechat-data-provider", - "version": "0.1.1", + "version": "0.1.2", "license": "ISC", "dependencies": { "@tanstack/react-query": "^4.28.0", @@ -26666,9 +26666,9 @@ } }, "@anthropic-ai/sdk": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.5.8.tgz", - "integrity": "sha512-iHenjcE2Q/az6VZiP1DueOSvKNRmxsly6Rx2yjJBoy7OBYVFGVjEdgs2mPQHtTX0ibKAR7tPq6F6MQbKDPWcKg==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.5.9.tgz", + "integrity": "sha512-9/TYca4qSe0xG40LLNf5vemybw5JAKF5OE6Eiyc+O+h3+VGGPeOKo+1SHaWBP5zS7bGX2o3Ne6EonPWyh9oNqA==", "requires": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", @@ -30080,7 +30080,7 @@ "lodash": "^4.17.21", "meilisearch": "^0.33.0", "mongoose": "^7.1.1", - "nodemailer": "^6.9.1", + "nodemailer": "^6.9.4", "nodemon": "^2.0.20", "openai": "^3.2.1", "openid-client": "^5.4.2", @@ -31735,9 +31735,9 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/react": { - "version": "18.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.17.tgz", - "integrity": "sha512-u+e7OlgPPh+aryjOm5UJMX32OvB2E3QASOAqVMY6Ahs90djagxwv2ya0IctglNbNTexC12qCSMZG47KPfy1hAA==", + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.18.tgz", + "integrity": "sha512-da4NTSeBv/P34xoZPhtcLkmZuJ+oYaCxHmyHzwaDQo9RQPBeXV+06gEk2FpqEcsX9XrnNLvRpVh6bdavDSjtiQ==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -31935,12 +31935,12 @@ } }, "@vitejs/plugin-react": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.3.tgz", - "integrity": "sha512-pwXDog5nwwvSIzwrvYYmA2Ljcd/ZNlcsSG2Q9CNDBwnsd55UGAyr2doXtB5j+2uymRCnCfExlznzzSFbBRcoCg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.4.tgz", + "integrity": "sha512-7wU921ABnNYkETiMaZy7XqpueMnpu5VxvVps13MjmCo+utBdD79sZzrApHawHtVX66cCJQQTXFcjH0y9dSUK8g==", "dev": true, "requires": { - "@babel/core": "^7.22.5", + "@babel/core": "^7.22.9", "@babel/plugin-transform-react-jsx-self": "^7.22.5", "@babel/plugin-transform-react-jsx-source": "^7.22.5", "react-refresh": "^0.14.0" @@ -33302,14 +33302,14 @@ } }, "browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.11" } }, @@ -33441,9 +33441,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001517", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz", - "integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==", + "version": "1.0.30001518", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001518.tgz", + "integrity": "sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA==", "dev": true }, "ccount": { @@ -34230,9 +34230,9 @@ } }, "dedent": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.3.0.tgz", - "integrity": "sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, "requires": {} }, @@ -34538,9 +34538,9 @@ } }, "electron-to-chromium": { - "version": "1.4.477", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.477.tgz", - "integrity": "sha512-shUVy6Eawp33dFBFIoYbIwLHrX0IZ857AlH9ug2o4rvbWmpaCUdBpQ5Zw39HRrfzAFm4APJE9V+E2A/WB0YqJw==", + "version": "1.4.478", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.478.tgz", + "integrity": "sha512-qjTA8djMXd+ruoODDFGnRCRBpID+AAfYWCyGtYTNhsuwxI19s8q19gbjKTwRS5z/LyVf5wICaIiPQGLekmbJbA==", "dev": true }, "elliptic": { @@ -38876,9 +38876,9 @@ } }, "langsmith": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.0.15.tgz", - "integrity": "sha512-SVLJEm94aK9mmqE3z2wlpzLjPNodnPJHp1MZdmXG2ysUWSFsRVuGkd6A/GTzlEZ6OofyJSOg6tcNFJSFOi13QQ==", + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.0.16.tgz", + "integrity": "sha512-HD97KJaSpCcuixbjfRhpSFdo5rWz28OJiUVs5uBRZDKUN2Amg4PWd0NFzGO3xC8osnjPPRvgH9by6Ige79hjxQ==", "requires": { "@types/uuid": "^9.0.1", "commander": "^10.0.1", diff --git a/packages/data-provider/src/types.ts b/packages/data-provider/src/types.ts index 76997a63e1..c48db00883 100644 --- a/packages/data-provider/src/types.ts +++ b/packages/data-provider/src/types.ts @@ -257,6 +257,7 @@ export type TStartupConfig = { serverDomain: string; registrationEnabled: boolean; socialLoginEnabled: boolean; + emailEnabled: boolean; }; export type TRefreshTokenResponse = { @@ -265,7 +266,8 @@ export type TRefreshTokenResponse = { }; export type TRequestPasswordResetResponse = { - link: string; + link?: string; + message?: string; }; export type File = {