slave 0.4.0

Laravel-inspired CLI for Rust MCP servers: scaffold apps whose business operations are MCP tools over Streamable HTTP, with built-in auth, users, roles and Turso migrations
//! Persistence for bearer tokens (stored as SHA-256 hashes).

use slave_framework::turso::{Connection, Error, Result};

/// Stores a token hash valid for `ttl_days` and returns its expiry timestamp.
pub async fn insert(
    conn: &Connection,
    user_id: i64,
    token_hash: &str,
    ttl_days: u32,
) -> Result<String> {
    let mut rows = conn
        .query(
            "INSERT INTO auth_tokens (user_id, token_hash, expires_at)
             VALUES (?1, ?2, datetime('now', ?3)) RETURNING expires_at",
            (user_id, token_hash, format!("+{ttl_days} days")),
        )
        .await?;
    match rows.next().await? {
        Some(row) => row.get(0),
        None => Err(Error::QueryReturnedNoRows),
    }
}

/// Revokes a token; returns `false` if it did not exist.
pub async fn delete(conn: &Connection, token_hash: &str) -> Result<bool> {
    let removed = conn
        .execute(
            "DELETE FROM auth_tokens WHERE token_hash = ?1",
            (token_hash,),
        )
        .await?;
    Ok(removed > 0)
}

/// Removes a user's expired tokens so the table does not grow forever.
pub async fn delete_expired_for_user(conn: &Connection, user_id: i64) -> Result<()> {
    conn.execute(
        "DELETE FROM auth_tokens WHERE user_id = ?1 AND expires_at <= CURRENT_TIMESTAMP",
        (user_id,),
    )
    .await?;
    Ok(())
}