Skip to main content

better_auth_api/plugins/email_password/
callbacks.rs

1use super::{EmailPasswordConfig, EmailPasswordPlugin};
2use crate::plugins::endpoint_context::{EndpointContext, WithCallbacks};
3use better_auth_core::{
4    AuthPlugin, AuthResult, AuthSchema, background::BackgroundFuture, wire::UserView,
5};
6use std::sync::Arc;
7
8type ExistingUserSender<S> = dyn Fn(&UserView, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
9    + Send
10    + Sync;
11
12/// Enumeration-safe signup notification with its active transaction and request.
13pub struct EmailPasswordCallbacks<S: AuthSchema> {
14    sender: Arc<ExistingUserSender<S>>,
15}
16impl<S: AuthSchema> EmailPasswordCallbacks<S> {
17    /// Construct notification work before scheduling. `None` completes synchronously.
18    pub fn existing_user_sign_up(
19        sender: impl Fn(&UserView, &EndpointContext<'_, S>) -> AuthResult<Option<BackgroundFuture>>
20        + Send
21        + Sync
22        + 'static,
23    ) -> Self {
24        Self {
25            sender: Arc::new(sender),
26        }
27    }
28}
29impl EmailPasswordPlugin {
30    /// Attach typed notification callbacks after configuring the password options.
31    pub fn callbacks<S: AuthSchema>(
32        self,
33        callbacks: EmailPasswordCallbacks<S>,
34    ) -> impl AuthPlugin<S> {
35        WithCallbacks {
36            plugin: self,
37            callbacks: Arc::new(callbacks),
38        }
39    }
40}
41pub(super) fn delivery<S: AuthSchema>(
42    config: &EmailPasswordConfig,
43    user: &UserView,
44    endpoint: &EndpointContext<'_, S>,
45) -> AuthResult<Option<BackgroundFuture>> {
46    if let Some(callbacks) = endpoint
47        .auth
48        .extensions
49        .get::<Arc<EmailPasswordCallbacks<S>>>()
50    {
51        return (callbacks.sender)(user, endpoint);
52    }
53    let Some(sender) = config.on_existing_user_sign_up.clone() else {
54        return Ok(None);
55    };
56    let user = user.clone();
57    let request = endpoint.request.cloned();
58    Ok(Some(Box::pin(async move {
59        sender
60            .on_existing_user_sign_up(&user, request.as_ref())
61            .await
62    })))
63}