// SPDX-FileCopyrightText: 2026 Progmasoft // SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 namespace Progmasoft.Progmaweb.Api.Accounts; /// Persistence of accounts and sessions. /// /// The store owns the uniqueness rules: account name, email address and Google identity are each unique, and a /// creation that would break one of them is refused atomically. It offers no enumeration of accounts and no way to /// delete one; the only removal in bulk is that of sessions that have already expired. /// internal interface IAccountStore { /// Stores a new account unless its name, email address or Google identity is taken. /// The account to store, with its normalized keys filled in. /// Cancels the operation. /// The stored account, or the uniqueness rule that refused it. ValueTask CreateAsync(AccountRecord account, CancellationToken cancellationToken); /// Finds an account by its normalized email address. /// Upper-case email address, as produces it. /// Cancels the operation. /// The account, or when no account has this address. ValueTask FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken); /// Finds the account linked to a Google identity. /// Subject identifier Google issued for the identity. /// Cancels the operation. /// The account, or when the identity is not linked. ValueTask FindByGoogleSubjectAsync(string googleSubject, CancellationToken cancellationToken); /// Finds an account by its identifier. /// Identifier of the account. /// Cancels the operation. /// The account, or when it does not exist. ValueTask FindByIdAsync(Guid id, CancellationToken cancellationToken); /// Finds an account by its normalized name. /// /// Upper-case account name, as produces it. /// /// Cancels the operation. /// The account, or when no account has this name. ValueTask FindByAccountNameAsync(string normalizedAccountName, CancellationToken cancellationToken); /// Stores a session, replacing one with the same token digest. /// The session to store. /// Cancels the operation. /// A task that completes when the session is stored. ValueTask StoreSessionAsync(SessionRecord session, CancellationToken cancellationToken); /// Finds a session by the digest of its token. /// SHA-256 digest of the session token. /// Cancels the operation. /// The session, or when it does not exist or was revoked. ValueTask FindSessionAsync(byte[] tokenDigest, CancellationToken cancellationToken); /// Removes a session. Revoking an unknown session is not an error. /// SHA-256 digest of the session token. /// Cancels the operation. /// A task that completes when the session is gone. ValueTask RevokeSessionAsync(byte[] tokenDigest, CancellationToken cancellationToken); /// Removes every session that has expired. /// A session has expired when its expiry is not later than . /// The current moment, in UTC. /// Cancels the operation. /// The number of sessions that were removed. ValueTask RemoveExpiredSessionsAsync(DateTimeOffset now, CancellationToken cancellationToken); }