//! Session liveness — two complementary axes.
//!
//! # Per-request session-row check ([`SessionLiveness`])
//!
//! Phase 11.Z 0.10.0 (RFC_2026-05-08 §4.2 lock). The verifier-side L2
//! port: "is the bearer token's session row still alive in the
//! consumer's own DB?" Wired into
//! [`crate::PasJwtVerifier::with_session_liveness`]. Always available
//! (no feature gate) — the port itself has no AES / OAuth deps.
//!
//! # Periodic PAS refresh-token check (`feature = "session-liveness"`)
//!
//! When a consumer persists PAS `refresh_token`s server-side and treats
//! PAS as the single source of truth for session validity, the code path
//! is always the same:
//!
//! 1. Encrypt the `refresh_token` at rest.
//! 2. Periodically ask PAS "is this session still live?" via
//!    [`attempt_liveness_refresh`].
//! 3. Distinguish a *revoked* session from a *transient* failure.
//!
//! This half ships behind `feature = "session-liveness"`:
//!
//! - [`TokenCipher`] — AES-256-GCM wrapper for at-rest encryption.
//! - [`LivenessOutcome`] — classification of a single liveness attempt.
//! - [`attempt_liveness_refresh`] — the decrypt → call PAS →
//!   re-encrypt sequence wrapped as one call. Generic over
//!   `P: PasAuthPort`.
//!
//! See `pas_external::pas_port` for the underlying port.
//!
//! Both halves answer "is this user's session valid?" at different
//! layers and cadences — one shared umbrella module keeps the surface
//! coherent. The 0.10.0 lookup port has no `aes-gcm` / `oauth`
//! transitive deps, so consumers can use L2 row-checks without pulling
//! the AES wrapper.

mod lookup;
#[cfg(feature = "session-liveness")]
mod cipher;
#[cfg(feature = "session-liveness")]
mod liveness;

pub use lookup::{SessionLiveness, SessionLivenessError};
#[cfg(feature = "session-liveness")]
pub use cipher::{CipherError, EncryptedRefreshToken, TokenCipher};
#[cfg(feature = "session-liveness")]
pub use liveness::{
    LivenessFailure, LivenessOutcome, RevokeCause, TransientCause, attempt_liveness_refresh,
};
