[package]
name = "keysat"
version = "0.1.0"
edition = "2021"
rust-version = "1.75"
description = "Keysat — self-hosted Bitcoin-paid software licensing server for Start9"
license-file = "LICENSE"
publish = false

[[bin]]
name = "keysat"
path = "src/main.rs"

[dependencies]
# HTTP server
axum = { version = "0.7", features = ["macros"] }
tower = "0.4"
tower-http = { version = "0.5", features = ["trace", "cors", "limit"] }
hyper = "1"

# Async runtime
tokio = { version = "1", features = ["full"] }

# Trait objects with async methods. The new `PaymentProvider` trait
# (src/payment/mod.rs) uses `#[async_trait]` for object-safe async fns.
# Could move to native AFIT in Rust 1.75+ but `async_trait` is one
# attribute and behaves identically.
async-trait = "0.1"

# Database (SQLite via sqlx). `macros` is required for the `sqlx::migrate!`
# macro that bakes ./migrations/*.sql into the binary at compile time. We
# only use the macros that don't need a live DB (no `query!` calls in the
# codebase), so enabling `macros` doesn't impose any compile-time database
# requirement.
sqlx = { version = "0.7", default-features = false, features = [
    "runtime-tokio-rustls",
    "sqlite",
    "migrate",
    "macros",
    "chrono",
    "uuid",
] }

# Cryptography. ed25519-dalek 2.x re-exports the `pkcs8` trait module from
# the lightweight `ed25519` crate, which doesn't include the `LineEnding`
# enum we need. So we depend on the underlying `pkcs8` crate directly with
# its `pem` feature for that one type.
ed25519-dalek = { version = "2", features = ["rand_core", "pkcs8", "pem"] }
pkcs8 = { version = "0.10", features = ["pem"] }
rand = "0.8"
sha2 = "0.10"
hmac = "0.12"
subtle = "2"
# Web-UI password hashing. Argon2id is the modern PHC-recommended default;
# this is the reference implementation in pure Rust (no FFI).
argon2 = "0.5"

# Encoding
data-encoding = "2" # Crockford base32 for license keys
base64 = "0.22"
hex = "0.4"

# Serialization
serde = { version = "1", features = ["derive"] }
serde_json = "1"
toml = "0.8"

# Time & IDs
chrono = { version = "0.4", features = ["serde"] }
uuid = { version = "1", features = ["v4", "serde"] }

# HTTP client (BTCPay)
reqwest = { version = "0.12", default-features = false, features = [
    "json",
    "rustls-tls",
] }

# Errors
anyhow = "1"
thiserror = "1"

# Logging
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

# Config
dotenvy = "0.15"

# URL/HTML helpers (used by BTCPay authorize-flow endpoints)
urlencoding = "2"
url = "2"
html-escape = "0.2"

# Embed the static admin web UI assets into the binary at compile time.
# The web/ directory is bundled directly into the runtime binary via
# rust-embed so that at runtime axum can serve /admin/* without needing
# any files copied alongside the binary.
rust-embed = { version = "8", features = ["mime-guess"] }
mime_guess = "2"

[dev-dependencies]
# Each integration test gets its own throwaway sqlite file. tempfile gives
# us NamedTempFile so the OS cleans up if a test panics mid-run.
tempfile = "3"

# tower in main deps is feature-minimal (only what axum needs). Tests use
# `ServiceExt::oneshot` to drive the router without bringing up an HTTP
# listener — that lives behind the `util` feature.
tower = { version = "0.4", features = ["util"] }

[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 1
strip = true
