pas-external 0.14.1

Ppoppo Accounts System (PAS) external SDK — OAuth2 PKCE, JWT verification port, Axum middleware, session liveness
Documentation
//! sv-axis (`session_version`) enforcement port + first-party adapters.
//!
//! Phase 11.Z (RFC_2026-05-09 §3.5 Row 4*/5*) — the SDK boundary's
//! re-export of the engine's `EpochRevocation` port plus the canonical
//! adapter set consumers wire at boot:
//!
//! - [`Cache`] / [`Fetcher`] — narrow port traits (promoted from
//!   chat-auth's `validator.rs` `SessionVersionCache` / `SessionVersionFetcher`
//!   pair under §3 Row 6 "replace, don't layer").
//! - [`InProcessTtlCache`] — opinionated [`Cache`] impl (per-pod TTL map).
//! - [`SharedCacheCache`] (gated `feature = "shared-cache"`) — adapter
//!   bridging `ppoppo_infra::Cache` (KVRocks via the canonical
//!   `STANDARDS_SHARED_CACHE.md §3.1` `sv:{sub}` namespace) to
//!   [`Cache`]. RFC_2026-05-08 §4.1 lock — promoted from chat-api's
//!   `session_version::KvCache` adapter (replace, don't layer).
//! - [`CompositeEpochRevocation`] — combines a [`Cache`] + a [`Fetcher`]
//!   into the engine port. Cache hit short-circuits; cache miss fetches
//!   authoritative + writes back. Fetcher transient surfaces as
//!   [`EpochRevocationError::Transient`], engine maps to
//!   [`AuthError::SessionVersionLookupUnavailable`], SDK maps to
//!   [`crate::TokenVerifyError::SessionVersionLookupUnavailable`].
//!
//! ## 0.10.0 BREAKING — `UserinfoFetcher` removed
//!
//! `UserinfoFetcher` was deleted in 0.10.0. The 0.9.0 framing was
//! misleading — PAS's userinfo authenticates the *caller*, not an
//! arbitrary queried subject, so `Fetcher::fetch(sub)` ignored `_sub`.
//! Zero consumers across the workspace verified 2026-05-08. Replacement
//! for per-user sv readout: [`SharedCacheCache`] over the canonical
//! KVRocks `sv:{sub}` key (proper per-user shape). Cache-miss fetcher
//! choice is consumer-specific: chat-api wires a cross-schema
//! `PgFetcher`; RCW/CTW wire none (they opted out of the sv-axis). The
//! deferred PAS per-user readout design lives in
//! `STANDARDS_AUTH_INVALIDATION §5.4.1`.
//!
//! ## Why HIDDEN sv on `Claims`, surfaced via the cache substrate
//!
//! The engine deliberately HIDES `sv` on `Claims` (Phase 4 Decision 1,
//! `ppoppo_token::access_token::claims`). Surfacing the *token's* sv
//! would push enforcement onto every caller. The cache substrate
//! reflects the *current authoritative value*, not the token's claim —
//! a different role. Consumers wiring this module never see the token's
//! sv; they hand authoritative-substrate lookups to the engine via
//! [`crate::JwtVerifier::with_epoch_revocation`].
//!
//! See `STANDARDS_AUTH_INVALIDATION §5` (sv-axis architecture intent +
//! SDK evolution history) for the architecture frame and SDK shape
//! locks (originating 0.9.0/0.10.0 RFCs retired 2026-05-21 — git
//! history).
//!
//! [`AuthError::SessionVersionLookupUnavailable`]: ppoppo_token::access_token::AuthError::SessionVersionLookupUnavailable

mod cache;
mod composite;
mod fetcher;
#[cfg(feature = "shared-cache")]
mod shared_cache;
mod ttl_cache;

pub use cache::Cache;
pub use composite::CompositeEpochRevocation;
pub use fetcher::{FetchError, Fetcher};
#[cfg(feature = "shared-cache")]
pub use shared_cache::SharedCacheCache;
pub use ttl_cache::InProcessTtlCache;

// Engine port re-export. The textbook deep module: small interface
// (`current(sub) -> Result<i64, _>`), large implementation
// (`engine::check_epoch::run` — R6 legacy admit, transient mapping,
// M37 observability, raw-payload sv extraction). Re-exporting here
// lets consumers depend only on `pas-external` without a transitive
// `ppoppo-token` Cargo entry.
pub use ppoppo_token::access_token::{EpochRevocation, EpochRevocationError};

// Shared key shape constants. PAS writes `sv:{sub}` to the canonical
// shared cache; consumers reading the same key share the namespace.
// SSOT lives in `ppoppo-token` so PAS writer and SDK consumer cannot
// drift.
pub use ppoppo_token::{SV_CACHE_TTL, sv_cache_key};