[package]
name = "noetl-server"
version = "2.60.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/noetl/noetl"
homepage = "https://noetl.io"
description = "NoETL Control Plane - Async Rust server for workflow orchestration"

[dependencies]
# Async runtime
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal", "time", "sync"] }

# Web framework
axum = { version = "0.8", features = ["macros"] }
# Phase 4a (noetl/ai-meta#61): opt-in TLS/mTLS listener.  `-no-provider`
# variant so axum-server doesn't pull aws-lc-rs — we build the rustls
# ServerConfig with the `ring` provider the rest of the stack already uses.
axum-server = { version = "0.7", default-features = false, features = ["tls-rustls-no-provider"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] }
rustls-pemfile = "2"
tower = "0.5"
tower-http = { version = "0.6", features = ["cors", "trace"] }

# Serialization
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_yaml = "0.9"

# Shared event envelope (noetl/ai-meta#49 EE-4): the canonical
# `ExecutorEvent` shape lives in the dedicated `noetl-events` crate
# extracted from `noetl-executor::events` in noetl/cli#49 + #50.
# Server takes a direct dep so the wire format the worker emits
# (via `noetl-executor::events::ExecutorEvent`) and the wire format
# the server's `POST /api/events` handler accepts as `EventRequest`
# are anchored to a single source of truth — instead of being held
# in sync by hand-aligned doc comments + parallel tests.
#
# The server's `EventRequest` legitimately carries extra fields
# the canonical envelope doesn't expose (`result_kind`, `result_uri`,
# `event_ids`, `actionable`, `informative`) and wire-encodes
# `execution_id` / `event_id` as `String` for JSON-number precision
# in browser clients, so it remains a distinct type.  The dep wires
# in `From<ExecutorEvent>` / `TryFrom<&EventRequest>` conversions +
# a wire-compat test that proves the shared subset round-trips.
noetl-events = "0.1"

# Database
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "chrono", "uuid", "json"] }

# Error handling
anyhow = "1.0"
thiserror = "2.0"

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

# NATS messaging
async-nats = "0.38"

# Templating (Jinja2-style)
minijinja = { version = "2.5", features = ["loader"] }

# Cryptography
aes-gcm = "0.10"
base64 = "0.22"
rand = "0.8"
async-trait = "0.1"
zeroize = "1"
# Constant-time comparison for bearer-token auth — see
# src/handlers/internal.rs (the `/api/internal/*` route gate).
subtle = "2.6"
# AWS SigV4 signing primitives for the AWS Secrets Manager provider
# (src/secrets/aws.rs).  All three are already in the lockfile as
# transitive deps; pin them directly so the provider compiles standalone.
sha2 = "0.10"
hmac = "0.12"
hex = "0.4"
# Secrets Wallet Phase 5a (noetl/ai-meta#61) — sealed payload primitives
# (src/crypto/sealed.rs).  X25519 ECDH + HKDF-SHA256 key derivation + ChaCha20-
# Poly1305 AEAD, no SDK dep tree.  The recipient (worker) holds a long-lived
# StaticSecret + PublicKey; the server uses an EphemeralSecret per call so the
# ECDH shared secret is single-use.
x25519-dalek = { version = "2", features = ["static_secrets"] }
chacha20poly1305 = "0.10"
hkdf = "0.12"
rand_core = "0.6"

# Utilities
uuid = { version = "1", features = ["serde", "v4"] }
chrono = { version = "0.4", features = ["serde"] }
dotenvy = "0.15"
envy = "0.4"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
ctor = "0.2"

# System info (for status endpoint)
sysinfo = "0.33"

# Regex (for ui_schema inline-directive scanning, etc.)
regex = "1"

# Prometheus metrics surface — exposed at GET /metrics per
# agents/rules/observability.md (Principle 1, Principle 2).
prometheus = "0.13"

# Stable hash for the shard-routing helper in src/sharding.rs
# (Phase F R2 of noetl/ai-meta#49).  Fixed-seed XxHash64; the
# output is fixed by the crate major version and the seed
# constant, so the shard assignment for a given execution_id +
# shard_count is stable across Rust releases, server restarts,
# and server replicas.  See the sharding-design page on the
# noetl/server wiki for why a stable hash matters.
twox-hash = "1.6"

[dev-dependencies]
tokio-test = "0.4"
# Process-global env var tests serialise via #[serial] so concurrent
# test threads don't race on NOETL_INTERNAL_API_TOKEN; see
# src/handlers/internal.rs tests.
serial_test = "3"

[[bin]]
name = "noetl-control-plane"
path = "src/main.rs"
