rustauth_plugins/last_login_method/
config.rs1use std::sync::Arc;
2use time::Duration;
3
4use super::resolve::LoginMethodContext;
5
6pub const DEFAULT_COOKIE_NAME: &str = "better-auth.last_used_login_method";
7pub const DEFAULT_COOKIE_MAX_AGE: Duration = Duration::days(30);
8pub const DEFAULT_DATABASE_FIELD_NAME: &str = "last_login_method";
9
10type LoginMethodResolver =
11 Arc<dyn Fn(&LoginMethodContext) -> Option<String> + Send + Sync + 'static>;
12
13#[derive(Clone, Default)]
15pub struct LastLoginMethodOptions {
16 pub cookie_name: Option<String>,
17 pub max_age: Option<Duration>,
18 pub resolver: Option<LoginMethodResolver>,
19 pub store_in_database: bool,
20 pub database_field_name: Option<String>,
21}
22
23impl LastLoginMethodOptions {
24 #[must_use]
25 pub fn builder() -> LastLoginMethodOptionsBuilder {
26 LastLoginMethodOptionsBuilder::default()
27 }
28
29 pub fn cookie_name(mut self, cookie_name: impl Into<String>) -> Self {
30 self.cookie_name = Some(cookie_name.into());
31 self
32 }
33
34 pub fn max_age(mut self, max_age: Duration) -> Self {
35 self.max_age = Some(max_age);
36 self
37 }
38
39 pub fn with_resolver<F>(mut self, resolver: F) -> Self
40 where
41 F: Fn(&LoginMethodContext) -> Option<String> + Send + Sync + 'static,
42 {
43 self.resolver = Some(Arc::new(resolver));
44 self
45 }
46
47 pub fn store_in_database(mut self, store_in_database: bool) -> Self {
48 self.store_in_database = store_in_database;
49 self
50 }
51
52 pub fn database_field_name(mut self, field_name: impl Into<String>) -> Self {
53 self.database_field_name = Some(field_name.into());
54 self
55 }
56
57 pub fn effective_cookie_name(&self) -> &str {
58 self.cookie_name.as_deref().unwrap_or(DEFAULT_COOKIE_NAME)
59 }
60
61 pub fn effective_max_age(&self) -> u64 {
62 self.max_age
63 .unwrap_or(DEFAULT_COOKIE_MAX_AGE)
64 .whole_seconds() as u64
65 }
66
67 pub fn effective_database_field_name(&self) -> &str {
68 self.database_field_name
69 .as_deref()
70 .unwrap_or(DEFAULT_DATABASE_FIELD_NAME)
71 }
72
73 pub fn resolve_login_method(&self, context: &LoginMethodContext) -> Option<String> {
74 self.resolver
75 .as_ref()
76 .and_then(|resolver| resolver(context))
77 .or_else(|| super::resolve::default_login_method(context))
78 }
79}
80
81#[derive(Clone, Default)]
82pub struct LastLoginMethodOptionsBuilder {
83 cookie_name: Option<String>,
84 max_age: Option<Duration>,
85 resolver: Option<LoginMethodResolver>,
86 store_in_database: Option<bool>,
87 database_field_name: Option<String>,
88}
89
90impl LastLoginMethodOptionsBuilder {
91 #[must_use]
92 pub fn cookie_name(mut self, cookie_name: impl Into<String>) -> Self {
93 self.cookie_name = Some(cookie_name.into());
94 self
95 }
96
97 #[must_use]
98 pub fn max_age(mut self, max_age: Duration) -> Self {
99 self.max_age = Some(max_age);
100 self
101 }
102
103 #[must_use]
104 pub fn with_resolver<F>(mut self, resolver: F) -> Self
105 where
106 F: Fn(&LoginMethodContext) -> Option<String> + Send + Sync + 'static,
107 {
108 self.resolver = Some(Arc::new(resolver));
109 self
110 }
111
112 #[must_use]
113 pub fn store_in_database(mut self, store_in_database: bool) -> Self {
114 self.store_in_database = Some(store_in_database);
115 self
116 }
117
118 #[must_use]
119 pub fn database_field_name(mut self, field_name: impl Into<String>) -> Self {
120 self.database_field_name = Some(field_name.into());
121 self
122 }
123
124 #[must_use]
125 pub fn build(self) -> LastLoginMethodOptions {
126 let defaults = LastLoginMethodOptions::default();
127 LastLoginMethodOptions {
128 cookie_name: self.cookie_name.or(defaults.cookie_name),
129 max_age: self.max_age.or(defaults.max_age),
130 resolver: self.resolver.or(defaults.resolver),
131 store_in_database: self.store_in_database.unwrap_or(defaults.store_in_database),
132 database_field_name: self.database_field_name.or(defaults.database_field_name),
133 }
134 }
135}