Skip to main content

better_auth_core/adapters/
memory.rs

1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex};
5use uuid::Uuid;
6
7use crate::error::{AuthError, AuthResult};
8use crate::types::{
9    Account, ApiKey, CreateAccount, CreateApiKey, CreateInvitation, CreateMember,
10    CreateOrganization, CreatePasskey, CreateSession, CreateTwoFactor, CreateUser,
11    CreateVerification, Invitation, InvitationStatus, Member, Organization, Passkey, Session,
12    TwoFactor, UpdateAccount, UpdateApiKey, UpdateOrganization, UpdateUser, User, Verification,
13};
14
15pub use super::memory_traits::{
16    MemoryAccount, MemoryApiKey, MemoryInvitation, MemoryMember, MemoryOrganization, MemoryPasskey,
17    MemorySession, MemoryTwoFactor, MemoryUser, MemoryVerification,
18};
19
20use super::traits::{
21    AccountOps, ApiKeyOps, InvitationOps, MemberOps, OrganizationOps, PasskeyOps, SessionOps,
22    TwoFactorOps, UserOps, VerificationOps,
23};
24
25/// In-memory database adapter for testing and development.
26///
27/// Generic over entity types — use default type parameters for the built-in
28/// types, or supply your own custom structs that implement the `Memory*`
29/// traits.
30///
31/// ```rust,ignore
32/// // Using built-in types (no turbofish needed):
33/// let adapter = MemoryDatabaseAdapter::new();
34///
35/// // Using custom types:
36/// let adapter = MemoryDatabaseAdapter::<MyUser, MySession, MyAccount,
37///     MyOrg, MyMember, MyInvitation, MyVerification>::new();
38/// ```
39pub struct MemoryDatabaseAdapter<
40    U = User,
41    S = Session,
42    A = Account,
43    O = Organization,
44    M = Member,
45    I = Invitation,
46    V = Verification,
47    P = Passkey,
48> {
49    users: Arc<Mutex<HashMap<String, U>>>,
50    sessions: Arc<Mutex<HashMap<String, S>>>,
51    accounts: Arc<Mutex<HashMap<String, A>>>,
52    verifications: Arc<Mutex<HashMap<String, V>>>,
53    email_index: Arc<Mutex<HashMap<String, String>>>,
54    username_index: Arc<Mutex<HashMap<String, String>>>,
55    organizations: Arc<Mutex<HashMap<String, O>>>,
56    members: Arc<Mutex<HashMap<String, M>>>,
57    invitations: Arc<Mutex<HashMap<String, I>>>,
58    slug_index: Arc<Mutex<HashMap<String, String>>>,
59    two_factors: Arc<Mutex<HashMap<String, TwoFactor>>>,
60    api_keys: Arc<Mutex<HashMap<String, ApiKey>>>,
61    passkeys: Arc<Mutex<HashMap<String, P>>>,
62    passkey_credential_index: Arc<Mutex<HashMap<String, String>>>,
63}
64
65/// Constructor for the default (built-in) entity types.
66/// Use `Default::default()` for custom type parameterizations.
67impl MemoryDatabaseAdapter {
68    pub fn new() -> Self {
69        Self::default()
70    }
71}
72
73impl<U, S, A, O, M, I, V, P> Default for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P> {
74    fn default() -> Self {
75        Self {
76            users: Arc::new(Mutex::new(HashMap::new())),
77            sessions: Arc::new(Mutex::new(HashMap::new())),
78            accounts: Arc::new(Mutex::new(HashMap::new())),
79            verifications: Arc::new(Mutex::new(HashMap::new())),
80            email_index: Arc::new(Mutex::new(HashMap::new())),
81            username_index: Arc::new(Mutex::new(HashMap::new())),
82            organizations: Arc::new(Mutex::new(HashMap::new())),
83            members: Arc::new(Mutex::new(HashMap::new())),
84            invitations: Arc::new(Mutex::new(HashMap::new())),
85            slug_index: Arc::new(Mutex::new(HashMap::new())),
86            two_factors: Arc::new(Mutex::new(HashMap::new())),
87            api_keys: Arc::new(Mutex::new(HashMap::new())),
88            passkeys: Arc::new(Mutex::new(HashMap::new())),
89            passkey_credential_index: Arc::new(Mutex::new(HashMap::new())),
90        }
91    }
92}
93
94// -- UserOps --
95
96#[async_trait]
97impl<U, S, A, O, M, I, V, P> UserOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
98where
99    U: MemoryUser,
100    S: MemorySession,
101    A: MemoryAccount,
102    O: MemoryOrganization,
103    M: MemoryMember,
104    I: MemoryInvitation,
105    V: MemoryVerification,
106    P: MemoryPasskey,
107{
108    type User = U;
109
110    async fn create_user(&self, create_user: CreateUser) -> AuthResult<U> {
111        let mut users = self.users.lock().unwrap();
112        let mut email_index = self.email_index.lock().unwrap();
113        let mut username_index = self.username_index.lock().unwrap();
114
115        let id = create_user
116            .id
117            .clone()
118            .unwrap_or_else(|| Uuid::new_v4().to_string());
119
120        if let Some(email) = &create_user.email
121            && email_index.contains_key(email)
122        {
123            return Err(AuthError::config("Email already exists"));
124        }
125
126        if let Some(username) = &create_user.username
127            && username_index.contains_key(username)
128        {
129            return Err(AuthError::conflict(
130                "A user with this username already exists",
131            ));
132        }
133
134        let now = Utc::now();
135        let user = U::from_create(id.clone(), &create_user, now);
136
137        users.insert(id.clone(), user.clone());
138
139        if let Some(email) = &create_user.email {
140            email_index.insert(email.clone(), id.clone());
141        }
142        if let Some(username) = &create_user.username {
143            username_index.insert(username.clone(), id);
144        }
145
146        Ok(user)
147    }
148
149    async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<U>> {
150        let users = self.users.lock().unwrap();
151        Ok(users.get(id).cloned())
152    }
153
154    async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<U>> {
155        let email_index = self.email_index.lock().unwrap();
156        let users = self.users.lock().unwrap();
157
158        if let Some(user_id) = email_index.get(email) {
159            Ok(users.get(user_id).cloned())
160        } else {
161            Ok(None)
162        }
163    }
164
165    async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<U>> {
166        let username_index = self.username_index.lock().unwrap();
167        let users = self.users.lock().unwrap();
168
169        if let Some(user_id) = username_index.get(username) {
170            Ok(users.get(user_id).cloned())
171        } else {
172            Ok(None)
173        }
174    }
175
176    async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<U> {
177        let mut users = self.users.lock().unwrap();
178        let mut email_index = self.email_index.lock().unwrap();
179        let mut username_index = self.username_index.lock().unwrap();
180
181        let user = users.get_mut(id).ok_or(AuthError::UserNotFound)?;
182
183        // Update indices BEFORE mutation (read old values via trait getters)
184        if let Some(new_email) = &update.email {
185            if let Some(old_email) = user.email() {
186                email_index.remove(old_email);
187            }
188            email_index.insert(new_email.clone(), id.to_string());
189        }
190
191        if let Some(ref new_username) = update.username {
192            if let Some(old_username) = user.username() {
193                username_index.remove(old_username);
194            }
195            username_index.insert(new_username.clone(), id.to_string());
196        }
197
198        user.apply_update(&update);
199        Ok(user.clone())
200    }
201
202    async fn delete_user(&self, id: &str) -> AuthResult<()> {
203        let mut users = self.users.lock().unwrap();
204        let mut email_index = self.email_index.lock().unwrap();
205        let mut username_index = self.username_index.lock().unwrap();
206
207        if let Some(user) = users.remove(id) {
208            if let Some(email) = user.email() {
209                email_index.remove(email);
210            }
211            if let Some(username) = user.username() {
212                username_index.remove(username);
213            }
214        }
215
216        Ok(())
217    }
218}
219
220// -- SessionOps --
221
222#[async_trait]
223impl<U, S, A, O, M, I, V, P> SessionOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
224where
225    U: MemoryUser,
226    S: MemorySession,
227    A: MemoryAccount,
228    O: MemoryOrganization,
229    M: MemoryMember,
230    I: MemoryInvitation,
231    V: MemoryVerification,
232    P: MemoryPasskey,
233{
234    type Session = S;
235
236    async fn create_session(&self, create_session: CreateSession) -> AuthResult<S> {
237        let mut sessions = self.sessions.lock().unwrap();
238
239        let id = Uuid::new_v4().to_string();
240        let token = format!("session_{}", Uuid::new_v4());
241        let now = Utc::now();
242        let session = S::from_create(id, token.clone(), &create_session, now);
243
244        sessions.insert(token, session.clone());
245        Ok(session)
246    }
247
248    async fn get_session(&self, token: &str) -> AuthResult<Option<S>> {
249        let sessions = self.sessions.lock().unwrap();
250        Ok(sessions.get(token).cloned())
251    }
252
253    async fn get_user_sessions(&self, user_id: &str) -> AuthResult<Vec<S>> {
254        let sessions = self.sessions.lock().unwrap();
255        Ok(sessions
256            .values()
257            .filter(|s| s.user_id() == user_id && s.active())
258            .cloned()
259            .collect())
260    }
261
262    async fn update_session_expiry(
263        &self,
264        token: &str,
265        expires_at: DateTime<Utc>,
266    ) -> AuthResult<()> {
267        let mut sessions = self.sessions.lock().unwrap();
268        if let Some(session) = sessions.get_mut(token) {
269            session.set_expires_at(expires_at);
270        }
271        Ok(())
272    }
273
274    async fn delete_session(&self, token: &str) -> AuthResult<()> {
275        let mut sessions = self.sessions.lock().unwrap();
276        sessions.remove(token);
277        Ok(())
278    }
279
280    async fn delete_user_sessions(&self, user_id: &str) -> AuthResult<()> {
281        let mut sessions = self.sessions.lock().unwrap();
282        sessions.retain(|_, s| s.user_id() != user_id);
283        Ok(())
284    }
285
286    async fn delete_expired_sessions(&self) -> AuthResult<usize> {
287        let mut sessions = self.sessions.lock().unwrap();
288        let now = Utc::now();
289        let initial_count = sessions.len();
290        sessions.retain(|_, s| s.expires_at() > now && s.active());
291        Ok(initial_count - sessions.len())
292    }
293
294    async fn update_session_active_organization(
295        &self,
296        token: &str,
297        organization_id: Option<&str>,
298    ) -> AuthResult<S> {
299        let mut sessions = self.sessions.lock().unwrap();
300        let session = sessions.get_mut(token).ok_or(AuthError::SessionNotFound)?;
301        session.set_active_organization_id(organization_id.map(|s| s.to_string()));
302        session.set_updated_at(Utc::now());
303        Ok(session.clone())
304    }
305}
306
307// -- AccountOps --
308
309#[async_trait]
310impl<U, S, A, O, M, I, V, P> AccountOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
311where
312    U: MemoryUser,
313    S: MemorySession,
314    A: MemoryAccount,
315    O: MemoryOrganization,
316    M: MemoryMember,
317    I: MemoryInvitation,
318    V: MemoryVerification,
319    P: MemoryPasskey,
320{
321    type Account = A;
322
323    async fn create_account(&self, create_account: CreateAccount) -> AuthResult<A> {
324        let mut accounts = self.accounts.lock().unwrap();
325
326        let id = Uuid::new_v4().to_string();
327        let now = Utc::now();
328        let account = A::from_create(id.clone(), &create_account, now);
329
330        accounts.insert(id, account.clone());
331        Ok(account)
332    }
333
334    async fn get_account(
335        &self,
336        provider: &str,
337        provider_account_id: &str,
338    ) -> AuthResult<Option<A>> {
339        let accounts = self.accounts.lock().unwrap();
340        Ok(accounts
341            .values()
342            .find(|acc| acc.provider_id() == provider && acc.account_id() == provider_account_id)
343            .cloned())
344    }
345
346    async fn get_user_accounts(&self, user_id: &str) -> AuthResult<Vec<A>> {
347        let accounts = self.accounts.lock().unwrap();
348        Ok(accounts
349            .values()
350            .filter(|acc| acc.user_id() == user_id)
351            .cloned()
352            .collect())
353    }
354
355    async fn update_account(&self, id: &str, update: UpdateAccount) -> AuthResult<A> {
356        let mut accounts = self.accounts.lock().unwrap();
357        let account = accounts
358            .get_mut(id)
359            .ok_or_else(|| AuthError::not_found("Account not found"))?;
360        account.apply_update(&update);
361        Ok(account.clone())
362    }
363
364    async fn delete_account(&self, id: &str) -> AuthResult<()> {
365        let mut accounts = self.accounts.lock().unwrap();
366        accounts.remove(id);
367        Ok(())
368    }
369}
370
371// -- VerificationOps --
372
373#[async_trait]
374impl<U, S, A, O, M, I, V, P> VerificationOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
375where
376    U: MemoryUser,
377    S: MemorySession,
378    A: MemoryAccount,
379    O: MemoryOrganization,
380    M: MemoryMember,
381    I: MemoryInvitation,
382    V: MemoryVerification,
383    P: MemoryPasskey,
384{
385    type Verification = V;
386
387    async fn create_verification(&self, create_verification: CreateVerification) -> AuthResult<V> {
388        let mut verifications = self.verifications.lock().unwrap();
389
390        let id = Uuid::new_v4().to_string();
391        let now = Utc::now();
392        let verification = V::from_create(id.clone(), &create_verification, now);
393
394        verifications.insert(id, verification.clone());
395        Ok(verification)
396    }
397
398    async fn get_verification(&self, identifier: &str, value: &str) -> AuthResult<Option<V>> {
399        let verifications = self.verifications.lock().unwrap();
400        let now = Utc::now();
401        Ok(verifications
402            .values()
403            .find(|v| v.identifier() == identifier && v.value() == value && v.expires_at() > now)
404            .cloned())
405    }
406
407    async fn get_verification_by_value(&self, value: &str) -> AuthResult<Option<V>> {
408        let verifications = self.verifications.lock().unwrap();
409        let now = Utc::now();
410        Ok(verifications
411            .values()
412            .find(|v| v.value() == value && v.expires_at() > now)
413            .cloned())
414    }
415
416    async fn get_verification_by_identifier(&self, identifier: &str) -> AuthResult<Option<V>> {
417        let verifications = self.verifications.lock().unwrap();
418        let now = Utc::now();
419        Ok(verifications
420            .values()
421            .find(|v| v.identifier() == identifier && v.expires_at() > now)
422            .cloned())
423    }
424
425    async fn consume_verification(&self, identifier: &str, value: &str) -> AuthResult<Option<V>> {
426        let mut verifications = self.verifications.lock().unwrap();
427        let now = Utc::now();
428
429        let matched_id = verifications
430            .iter()
431            .filter_map(|(id, verification)| {
432                if verification.identifier() == identifier
433                    && verification.value() == value
434                    && verification.expires_at() > now
435                {
436                    Some((id, verification.created_at()))
437                } else {
438                    None
439                }
440            })
441            .max_by_key(|(_, created_at)| *created_at)
442            .map(|(id, _)| id.clone());
443
444        if let Some(id) = matched_id {
445            Ok(verifications.remove(&id))
446        } else {
447            Ok(None)
448        }
449    }
450
451    async fn delete_verification(&self, id: &str) -> AuthResult<()> {
452        let mut verifications = self.verifications.lock().unwrap();
453        verifications.remove(id);
454        Ok(())
455    }
456
457    async fn delete_expired_verifications(&self) -> AuthResult<usize> {
458        let mut verifications = self.verifications.lock().unwrap();
459        let now = Utc::now();
460        let initial_count = verifications.len();
461        verifications.retain(|_, v| v.expires_at() > now);
462        Ok(initial_count - verifications.len())
463    }
464}
465
466// -- OrganizationOps --
467
468#[async_trait]
469impl<U, S, A, O, M, I, V, P> OrganizationOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
470where
471    U: MemoryUser,
472    S: MemorySession,
473    A: MemoryAccount,
474    O: MemoryOrganization,
475    M: MemoryMember,
476    I: MemoryInvitation,
477    V: MemoryVerification,
478    P: MemoryPasskey,
479{
480    type Organization = O;
481
482    async fn create_organization(&self, create_org: CreateOrganization) -> AuthResult<O> {
483        let mut organizations = self.organizations.lock().unwrap();
484        let mut slug_index = self.slug_index.lock().unwrap();
485
486        if slug_index.contains_key(&create_org.slug) {
487            return Err(AuthError::conflict("Organization slug already exists"));
488        }
489
490        let id = create_org
491            .id
492            .clone()
493            .unwrap_or_else(|| Uuid::new_v4().to_string());
494        let now = Utc::now();
495        let organization = O::from_create(id.clone(), &create_org, now);
496
497        organizations.insert(id.clone(), organization.clone());
498        slug_index.insert(create_org.slug.clone(), id);
499
500        Ok(organization)
501    }
502
503    async fn get_organization_by_id(&self, id: &str) -> AuthResult<Option<O>> {
504        let organizations = self.organizations.lock().unwrap();
505        Ok(organizations.get(id).cloned())
506    }
507
508    async fn get_organization_by_slug(&self, slug: &str) -> AuthResult<Option<O>> {
509        let slug_index = self.slug_index.lock().unwrap();
510        let organizations = self.organizations.lock().unwrap();
511
512        if let Some(org_id) = slug_index.get(slug) {
513            Ok(organizations.get(org_id).cloned())
514        } else {
515            Ok(None)
516        }
517    }
518
519    async fn update_organization(&self, id: &str, update: UpdateOrganization) -> AuthResult<O> {
520        let mut organizations = self.organizations.lock().unwrap();
521        let mut slug_index = self.slug_index.lock().unwrap();
522
523        let org = organizations
524            .get_mut(id)
525            .ok_or_else(|| AuthError::not_found("Organization not found"))?;
526
527        // Update slug index BEFORE mutation
528        if let Some(new_slug) = &update.slug {
529            let current_slug = org.slug().to_string();
530            if *new_slug != current_slug {
531                if slug_index.contains_key(new_slug.as_str()) {
532                    return Err(AuthError::conflict("Organization slug already exists"));
533                }
534                slug_index.remove(&current_slug);
535                slug_index.insert(new_slug.clone(), id.to_string());
536            }
537        }
538
539        org.apply_update(&update);
540        Ok(org.clone())
541    }
542
543    async fn delete_organization(&self, id: &str) -> AuthResult<()> {
544        let mut organizations = self.organizations.lock().unwrap();
545        let mut slug_index = self.slug_index.lock().unwrap();
546        let mut members = self.members.lock().unwrap();
547        let mut invitations = self.invitations.lock().unwrap();
548
549        if let Some(org) = organizations.remove(id) {
550            slug_index.remove(org.slug());
551        }
552
553        members.retain(|_, m| m.organization_id() != id);
554        invitations.retain(|_, i| i.organization_id() != id);
555
556        Ok(())
557    }
558
559    async fn list_user_organizations(&self, user_id: &str) -> AuthResult<Vec<O>> {
560        let members = self.members.lock().unwrap();
561        let organizations = self.organizations.lock().unwrap();
562
563        let org_ids: Vec<String> = members
564            .values()
565            .filter(|m| m.user_id() == user_id)
566            .map(|m| m.organization_id().to_string())
567            .collect();
568
569        let orgs = org_ids
570            .iter()
571            .filter_map(|id| organizations.get(id).cloned())
572            .collect();
573
574        Ok(orgs)
575    }
576}
577
578// -- MemberOps --
579
580#[async_trait]
581impl<U, S, A, O, M, I, V, P> MemberOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
582where
583    U: MemoryUser,
584    S: MemorySession,
585    A: MemoryAccount,
586    O: MemoryOrganization,
587    M: MemoryMember,
588    I: MemoryInvitation,
589    V: MemoryVerification,
590    P: MemoryPasskey,
591{
592    type Member = M;
593
594    async fn create_member(&self, create_member: CreateMember) -> AuthResult<M> {
595        let mut members = self.members.lock().unwrap();
596
597        let exists = members.values().any(|m| {
598            m.organization_id() == create_member.organization_id
599                && m.user_id() == create_member.user_id
600        });
601
602        if exists {
603            return Err(AuthError::conflict(
604                "User is already a member of this organization",
605            ));
606        }
607
608        let id = Uuid::new_v4().to_string();
609        let now = Utc::now();
610        let member = M::from_create(id.clone(), &create_member, now);
611
612        members.insert(id, member.clone());
613        Ok(member)
614    }
615
616    async fn get_member(&self, organization_id: &str, user_id: &str) -> AuthResult<Option<M>> {
617        let members = self.members.lock().unwrap();
618        Ok(members
619            .values()
620            .find(|m| m.organization_id() == organization_id && m.user_id() == user_id)
621            .cloned())
622    }
623
624    async fn get_member_by_id(&self, id: &str) -> AuthResult<Option<M>> {
625        let members = self.members.lock().unwrap();
626        Ok(members.get(id).cloned())
627    }
628
629    async fn update_member_role(&self, member_id: &str, role: &str) -> AuthResult<M> {
630        let mut members = self.members.lock().unwrap();
631        let member = members
632            .get_mut(member_id)
633            .ok_or_else(|| AuthError::not_found("Member not found"))?;
634        member.set_role(role.to_string());
635        Ok(member.clone())
636    }
637
638    async fn delete_member(&self, member_id: &str) -> AuthResult<()> {
639        let mut members = self.members.lock().unwrap();
640        members.remove(member_id);
641        Ok(())
642    }
643
644    async fn list_organization_members(&self, organization_id: &str) -> AuthResult<Vec<M>> {
645        let members = self.members.lock().unwrap();
646        Ok(members
647            .values()
648            .filter(|m| m.organization_id() == organization_id)
649            .cloned()
650            .collect())
651    }
652
653    async fn count_organization_members(&self, organization_id: &str) -> AuthResult<usize> {
654        let members = self.members.lock().unwrap();
655        Ok(members
656            .values()
657            .filter(|m| m.organization_id() == organization_id)
658            .count())
659    }
660
661    async fn count_organization_owners(&self, organization_id: &str) -> AuthResult<usize> {
662        let members = self.members.lock().unwrap();
663        Ok(members
664            .values()
665            .filter(|m| m.organization_id() == organization_id && m.role() == "owner")
666            .count())
667    }
668}
669
670// -- InvitationOps --
671
672#[async_trait]
673impl<U, S, A, O, M, I, V, P> InvitationOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
674where
675    U: MemoryUser,
676    S: MemorySession,
677    A: MemoryAccount,
678    O: MemoryOrganization,
679    M: MemoryMember,
680    I: MemoryInvitation,
681    V: MemoryVerification,
682    P: MemoryPasskey,
683{
684    type Invitation = I;
685
686    async fn create_invitation(&self, create_inv: CreateInvitation) -> AuthResult<I> {
687        let mut invitations = self.invitations.lock().unwrap();
688
689        let id = Uuid::new_v4().to_string();
690        let now = Utc::now();
691        let invitation = I::from_create(id.clone(), &create_inv, now);
692
693        invitations.insert(id, invitation.clone());
694        Ok(invitation)
695    }
696
697    async fn get_invitation_by_id(&self, id: &str) -> AuthResult<Option<I>> {
698        let invitations = self.invitations.lock().unwrap();
699        Ok(invitations.get(id).cloned())
700    }
701
702    async fn get_pending_invitation(
703        &self,
704        organization_id: &str,
705        email: &str,
706    ) -> AuthResult<Option<I>> {
707        let invitations = self.invitations.lock().unwrap();
708        Ok(invitations
709            .values()
710            .find(|i| {
711                i.organization_id() == organization_id
712                    && i.email().to_lowercase() == email.to_lowercase()
713                    && *i.status() == InvitationStatus::Pending
714            })
715            .cloned())
716    }
717
718    async fn update_invitation_status(&self, id: &str, status: InvitationStatus) -> AuthResult<I> {
719        let mut invitations = self.invitations.lock().unwrap();
720        let invitation = invitations
721            .get_mut(id)
722            .ok_or_else(|| AuthError::not_found("Invitation not found"))?;
723        invitation.set_status(status);
724        Ok(invitation.clone())
725    }
726
727    async fn list_organization_invitations(&self, organization_id: &str) -> AuthResult<Vec<I>> {
728        let invitations = self.invitations.lock().unwrap();
729        Ok(invitations
730            .values()
731            .filter(|i| i.organization_id() == organization_id)
732            .cloned()
733            .collect())
734    }
735
736    async fn list_user_invitations(&self, email: &str) -> AuthResult<Vec<I>> {
737        let invitations = self.invitations.lock().unwrap();
738        let now = Utc::now();
739        Ok(invitations
740            .values()
741            .filter(|i| {
742                i.email().to_lowercase() == email.to_lowercase()
743                    && *i.status() == InvitationStatus::Pending
744                    && i.expires_at() > now
745            })
746            .cloned()
747            .collect())
748    }
749}
750
751// -- TwoFactorOps --
752
753#[async_trait]
754impl<U, S, A, O, M, I, V, P> TwoFactorOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
755where
756    U: MemoryUser,
757    S: MemorySession,
758    A: MemoryAccount,
759    O: MemoryOrganization,
760    M: MemoryMember,
761    I: MemoryInvitation,
762    V: MemoryVerification,
763    P: MemoryPasskey,
764{
765    type TwoFactor = TwoFactor;
766
767    async fn create_two_factor(&self, create: CreateTwoFactor) -> AuthResult<TwoFactor> {
768        let mut two_factors = self.two_factors.lock().unwrap();
769
770        // Check if user already has 2FA
771        if two_factors.values().any(|tf| tf.user_id == create.user_id) {
772            return Err(AuthError::conflict(
773                "Two-factor authentication already enabled for this user",
774            ));
775        }
776
777        let id = Uuid::new_v4().to_string();
778        let now = Utc::now();
779        let two_factor: TwoFactor = MemoryTwoFactor::from_create(id.clone(), &create, now);
780
781        two_factors.insert(id, two_factor.clone());
782        Ok(two_factor)
783    }
784
785    async fn get_two_factor_by_user_id(&self, user_id: &str) -> AuthResult<Option<TwoFactor>> {
786        let two_factors = self.two_factors.lock().unwrap();
787        Ok(two_factors
788            .values()
789            .find(|tf| tf.user_id == user_id)
790            .cloned())
791    }
792
793    async fn update_two_factor_backup_codes(
794        &self,
795        user_id: &str,
796        backup_codes: &str,
797    ) -> AuthResult<TwoFactor> {
798        let mut two_factors = self.two_factors.lock().unwrap();
799        let two_factor = two_factors
800            .values_mut()
801            .find(|tf| tf.user_id == user_id)
802            .ok_or_else(|| AuthError::not_found("Two-factor record not found"))?;
803        two_factor.set_backup_codes(backup_codes.to_string());
804        Ok(two_factor.clone())
805    }
806
807    async fn delete_two_factor(&self, user_id: &str) -> AuthResult<()> {
808        let mut two_factors = self.two_factors.lock().unwrap();
809        two_factors.retain(|_, tf| tf.user_id != user_id);
810        Ok(())
811    }
812}
813
814// -- ApiKeyOps --
815
816#[async_trait]
817impl<U, S, A, O, M, I, V, P> ApiKeyOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
818where
819    U: MemoryUser,
820    S: MemorySession,
821    A: MemoryAccount,
822    O: MemoryOrganization,
823    M: MemoryMember,
824    I: MemoryInvitation,
825    V: MemoryVerification,
826    P: MemoryPasskey,
827{
828    type ApiKey = ApiKey;
829
830    async fn create_api_key(&self, input: CreateApiKey) -> AuthResult<ApiKey> {
831        let mut api_keys = self.api_keys.lock().unwrap();
832
833        if api_keys.values().any(|k| k.key_hash == input.key_hash) {
834            return Err(AuthError::conflict("API key already exists"));
835        }
836
837        let id = Uuid::new_v4().to_string();
838        let now = Utc::now();
839        let api_key: ApiKey = MemoryApiKey::from_create(id.clone(), &input, now);
840
841        api_keys.insert(id, api_key.clone());
842        Ok(api_key)
843    }
844
845    async fn get_api_key_by_id(&self, id: &str) -> AuthResult<Option<ApiKey>> {
846        let api_keys = self.api_keys.lock().unwrap();
847        Ok(api_keys.get(id).cloned())
848    }
849
850    async fn get_api_key_by_hash(&self, hash: &str) -> AuthResult<Option<ApiKey>> {
851        let api_keys = self.api_keys.lock().unwrap();
852        Ok(api_keys.values().find(|k| k.key_hash == hash).cloned())
853    }
854
855    async fn list_api_keys_by_user(&self, user_id: &str) -> AuthResult<Vec<ApiKey>> {
856        let api_keys = self.api_keys.lock().unwrap();
857        let mut keys: Vec<ApiKey> = api_keys
858            .values()
859            .filter(|k| k.user_id == user_id)
860            .cloned()
861            .collect();
862        keys.sort_by(|a, b| b.created_at.cmp(&a.created_at));
863        Ok(keys)
864    }
865
866    async fn update_api_key(&self, id: &str, update: UpdateApiKey) -> AuthResult<ApiKey> {
867        let mut api_keys = self.api_keys.lock().unwrap();
868        let api_key = api_keys
869            .get_mut(id)
870            .ok_or_else(|| AuthError::not_found("API key not found"))?;
871        api_key.apply_update(&update);
872        Ok(api_key.clone())
873    }
874
875    async fn delete_api_key(&self, id: &str) -> AuthResult<()> {
876        let mut api_keys = self.api_keys.lock().unwrap();
877        api_keys.remove(id);
878        Ok(())
879    }
880}
881
882// -- PasskeyOps --
883
884#[async_trait]
885impl<U, S, A, O, M, I, V, P> PasskeyOps for MemoryDatabaseAdapter<U, S, A, O, M, I, V, P>
886where
887    U: MemoryUser,
888    S: MemorySession,
889    A: MemoryAccount,
890    O: MemoryOrganization,
891    M: MemoryMember,
892    I: MemoryInvitation,
893    V: MemoryVerification,
894    P: MemoryPasskey,
895{
896    type Passkey = P;
897
898    async fn create_passkey(&self, input: CreatePasskey) -> AuthResult<P> {
899        let mut credential_index = self.passkey_credential_index.lock().unwrap();
900        let mut passkeys = self.passkeys.lock().unwrap();
901
902        if credential_index.contains_key(&input.credential_id) {
903            return Err(AuthError::conflict(
904                "A passkey with this credential ID already exists",
905            ));
906        }
907
908        let id = Uuid::new_v4().to_string();
909        let now = Utc::now();
910        let passkey = P::from_create(id.clone(), &input, now);
911
912        credential_index.insert(input.credential_id.clone(), id.clone());
913        passkeys.insert(id, passkey.clone());
914        Ok(passkey)
915    }
916
917    async fn get_passkey_by_id(&self, id: &str) -> AuthResult<Option<P>> {
918        let passkeys = self.passkeys.lock().unwrap();
919        Ok(passkeys.get(id).cloned())
920    }
921
922    async fn get_passkey_by_credential_id(&self, credential_id: &str) -> AuthResult<Option<P>> {
923        let passkey_id = {
924            let credential_index = self.passkey_credential_index.lock().unwrap();
925            credential_index.get(credential_id).cloned()
926        };
927
928        let passkeys = self.passkeys.lock().unwrap();
929
930        if let Some(id) = passkey_id {
931            Ok(passkeys.get(&id).cloned())
932        } else {
933            Ok(None)
934        }
935    }
936
937    async fn list_passkeys_by_user(&self, user_id: &str) -> AuthResult<Vec<P>> {
938        let passkeys = self.passkeys.lock().unwrap();
939        let mut matched: Vec<P> = passkeys
940            .values()
941            .filter(|p| p.user_id() == user_id)
942            .cloned()
943            .collect();
944        matched.sort_by_key(|p| std::cmp::Reverse(p.created_at()));
945        Ok(matched)
946    }
947
948    async fn update_passkey_counter(&self, id: &str, counter: u64) -> AuthResult<P> {
949        let mut passkeys = self.passkeys.lock().unwrap();
950        let passkey = passkeys
951            .get_mut(id)
952            .ok_or_else(|| AuthError::not_found("Passkey not found"))?;
953        passkey.set_counter(counter);
954        Ok(passkey.clone())
955    }
956
957    async fn update_passkey_name(&self, id: &str, name: &str) -> AuthResult<P> {
958        let mut passkeys = self.passkeys.lock().unwrap();
959        let passkey = passkeys
960            .get_mut(id)
961            .ok_or_else(|| AuthError::not_found("Passkey not found"))?;
962        passkey.set_name(name.to_string());
963        Ok(passkey.clone())
964    }
965
966    async fn delete_passkey(&self, id: &str) -> AuthResult<()> {
967        let mut credential_index = self.passkey_credential_index.lock().unwrap();
968        let mut passkeys = self.passkeys.lock().unwrap();
969
970        if let Some(passkey) = passkeys.remove(id) {
971            credential_index.remove(passkey.credential_id());
972        }
973        Ok(())
974    }
975}