use erp_core::events::EventBus; use sea_orm::DatabaseConnection; use uuid::Uuid; /// Auth-specific state extracted from the server's AppState via `FromRef`. /// /// This avoids a circular dependency between erp-auth and erp-server. /// The server crate implements `FromRef for AuthState` so that /// Axum handlers in erp-auth can extract `State` directly. /// /// Contains everything the auth handlers need: /// - Database connection for user/credential lookups /// - EventBus for publishing domain events /// - JWT configuration for token signing and validation /// - Default tenant ID for the bootstrap phase #[derive(Clone)] pub struct AuthState { pub db: DatabaseConnection, pub event_bus: EventBus, pub jwt_secret: String, pub access_ttl_secs: i64, pub refresh_ttl_secs: i64, pub default_tenant_id: Uuid, } /// Parse a human-readable TTL string (e.g. "15m", "7d", "1h", "900s") into seconds. /// /// Falls back to parsing the raw string as seconds if no unit suffix is recognized. pub fn parse_ttl(ttl: &str) -> i64 { let ttl = ttl.trim(); if let Some(num) = ttl.strip_suffix('s') { num.parse::().unwrap_or(900) } else if let Some(num) = ttl.strip_suffix('m') { num.parse::().map(|n| n * 60).unwrap_or(900) } else if let Some(num) = ttl.strip_suffix('h') { num.parse::().map(|n| n * 3600).unwrap_or(900) } else if let Some(num) = ttl.strip_suffix('d') { num.parse::().map(|n| n * 86400).unwrap_or(900) } else { ttl.parse::().unwrap_or(900) } } #[cfg(test)] mod tests { use super::*; #[test] fn parse_ttl_seconds() { assert_eq!(parse_ttl("900s"), 900); } #[test] fn parse_ttl_minutes() { assert_eq!(parse_ttl("15m"), 900); } #[test] fn parse_ttl_hours() { assert_eq!(parse_ttl("1h"), 3600); } #[test] fn parse_ttl_days() { assert_eq!(parse_ttl("7d"), 604800); } #[test] fn parse_ttl_raw_number() { assert_eq!(parse_ttl("300"), 300); } #[test] fn parse_ttl_fallback_on_invalid() { assert_eq!(parse_ttl("invalid"), 900); } }