Skip to main content

better_auth_core/
plugin_runtime.rs

1//! Per-instance bindings for plugin database hooks and user-field policies.
2
3use std::sync::{Arc, OnceLock, Weak};
4
5use crate::request_runtime::RuntimeIdentity;
6use crate::user_fields::UserConfig;
7use crate::{AuthContext, AuthError, AuthResult, AuthSchema};
8
9mod fields;
10pub use fields::ModelFields;
11
12struct Binding<S: AuthSchema> {
13    identity: RuntimeIdentity,
14    context: Weak<AuthContext<S>>,
15}
16
17/// A plugin's reference to its own authentication runtime.
18pub struct PluginRuntime<S: AuthSchema>(Arc<OnceLock<Binding<S>>>);
19
20impl<S: AuthSchema> Clone for PluginRuntime<S> {
21    fn clone(&self) -> Self {
22        Self(self.0.clone())
23    }
24}
25
26impl<S: AuthSchema> Default for PluginRuntime<S> {
27    fn default() -> Self {
28        Self(Arc::default())
29    }
30}
31
32impl<S: AuthSchema> PluginRuntime<S> {
33    /// Read this instance's active request context or its initialized context.
34    pub fn context(&self) -> AuthResult<Arc<AuthContext<S>>> {
35        self.0
36            .get()
37            .and_then(|binding| {
38                binding
39                    .identity
40                    .current()
41                    .or_else(|| binding.context.upgrade())
42            })
43            .ok_or_else(|| {
44                AuthError::config("Plugin runtime is not initialized or has been dropped")
45            })
46    }
47
48    /// Bind once after every plugin and store facade has been initialized.
49    pub fn bind(&self, context: &Arc<AuthContext<S>>) -> AuthResult<()> {
50        self.0
51            .set(Binding {
52                identity: context.runtime_identity(),
53                context: Arc::downgrade(context),
54            })
55            .map_err(|_| AuthError::config("Plugin runtime is already initialized"))
56    }
57}
58
59/// Resolved adapter policy. Endpoint policy remains in `AuthConfig::user`.
60#[derive(Clone)]
61pub struct AdapterUserFields(pub UserConfig);
62
63pub fn resolve_user_fields(
64    application: &UserConfig,
65    plugins: UserConfig,
66) -> (UserConfig, UserConfig) {
67    let mut adapter = plugins.clone();
68    if let Some(fields) = &application.additional_fields {
69        adapter.fields_mut().extend(fields.clone());
70    }
71    let mut endpoint = application.clone();
72    if let Some(fields) = plugins.additional_fields {
73        endpoint.fields_mut().extend(fields);
74    }
75    (adapter, endpoint)
76}