better_auth_core/user_fields/
transform.rs1use crate::FieldValue as Value;
2use crate::{AuthError, AuthResult};
3use std::{future::Future, pin::Pin, sync::Arc};
4
5type TransformResult = AuthResult<Value>;
6type TransformFuture = Pin<Box<dyn Future<Output = TransformResult> + Send>>;
7
8#[derive(Clone)]
10pub struct UserFieldTransform(Callback);
11
12#[derive(Clone)]
13enum Callback {
14 Sync(Arc<dyn Fn(Value) -> TransformResult + Send + Sync>),
15 Async(Arc<dyn Fn(Value) -> TransformFuture + Send + Sync>),
16}
17
18impl UserFieldTransform {
19 pub fn new(callback: impl Fn(Value) -> TransformResult + Send + Sync + 'static) -> Self {
21 Self(Callback::Sync(Arc::new(callback)))
22 }
23
24 pub fn new_async<F, Fut>(callback: F) -> Self
27 where
28 F: Fn(Value) -> Fut + Send + Sync + 'static,
29 Fut: Future<Output = TransformResult> + Send + 'static,
30 {
31 Self(Callback::Async(Arc::new(move |value| {
32 Box::pin(callback(value))
33 })))
34 }
35
36 pub async fn call(&self, value: Value) -> TransformResult {
38 match &self.0 {
39 Callback::Sync(callback) => callback(value),
40 Callback::Async(callback) => callback(value).await,
41 }
42 }
43
44 pub fn call_sync(&self, value: Value) -> TransformResult {
47 match &self.0 {
48 Callback::Sync(callback) => callback(value),
49 Callback::Async(_) => Err(AuthError::config(
50 "Async field transforms require an adapter boundary; public-input parsing is synchronous",
51 )),
52 }
53 }
54
55 pub(crate) fn is_async(&self) -> bool {
56 matches!(self.0, Callback::Async(_))
57 }
58}