class

KemalIdentity::Testing::MemorySessionRepository

Inherits KemalIdentity::Sessions::Repository < Reference < Object

In-memory Sessions::Repository.

Passes the same contract spec as the PostgreSQL adapter. Wired to an account repository because find_by_digest must return session state and account status together — the reference SQL is one indexed lookup with a join, and a double that returned session state alone would let a spec pass that the real adapter fails.

Constructors

new(accounts : MemoryAccountRepository)
Source

Instance methods

create(record : KemalIdentity::Sessions::Record) : Nil

Stores a new session.

Raises KemalIdentity::InfrastructureError if record.token_digest is already present. This is not defensive noise: auth_sessions.token_digest carries a unique index precisely so that a digest collision is a loud database error rather than a silent security failure in which two accounts share a session (docs/03-data-model.md). An implementation that upserted here would convert that error into exactly the failure the index exists to prevent.

Source
delete_expired(before : Time) : Int32

Deletes rows whose absolute_expires_at is at or before before, returning the count.

Disk reclamation only. Correctness never depends on this having run: expiry is evaluated on every read, which is the direct lesson of kemal-session issue #116, where a timeout only marked a session for deletion at the next GC pass and a read could refresh its access time before any expiry check, reviving it (docs/02-security-model.md).

Source
delete_revoked_before(before : Time) : Int32

Deletes revoked rows whose revoked_at is at or before before, returning the count.

Separate from #delete_expired because a revoked session is not necessarily an expired one: logging out at nine in the morning revokes a row whose absolute deadline is still hours away, and that row is worth keeping for a while. It is the evidence behind "you were signed out of this device", and deleting it the instant it is revoked throws away the only record that the logout happened.

The retention window is the application's to choose. Disk reclamation either way — correctness never depends on this having run, because revocation is evaluated on read.

Source
find_by_digest(digest : Bytes) : KemalIdentity::Sessions::Lookup | Nil

Resolves a session by the digest of its token, returning session state and account status together.

Returns nil — never raises — when nothing matches. "Unknown digest" is the ordinary case for an expired cookie, a tampered one, or one from a previous deployment.

Also returns nil when the session's account does not exist. The reference SQL is an inner join, so a session pointing at a deleted account resolves to nothing: the failure mode is closed, not open.

Revocation, expiry and account status are not evaluated here. This method reports facts; SessionService decides what they mean. That split is what lets the same repository serve a "list my devices" screen that wants to see revoked rows.

Source
revoke(id : String, at : Time) : Bool

Marks one session revoked, returning false if it does not exist or was already revoked.

Already-revoked returns false rather than raising: logging out twice is not an error, and the caller learns whether it changed anything.

Source
revoke_all_for_account(account_id : String, at : Time, except_id : String | Nil = nil) : Int32

Revokes every live session for an account, optionally sparing one, and returns how many it revoked.

except_id is what makes "log out everywhere else" and "change password without logging myself out" possible. Already-revoked sessions are not counted and not re-stamped, so the count is the number of sessions actually ended.

Source
size
Source
touch(id : String, last_seen_at : Time, idle_expires_at : Time) : Bool

Moves last_seen_at and idle_expires_at forward for one session.

Called only when the throttle in SessionService allows it, never on every request. Returns false if no such session exists.

Source