forge-runtime 0.10.0

Runtime executors and gateway for the Forge framework
Documentation
[package]
name = "forge-runtime"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Runtime executors and gateway for the Forge framework"

[lints]
workspace = true

[dependencies]
# Always required: core types, async runtime, database, serialization,
# tracing, concurrent maps. Every feature touches some of these.
forge-core = { version = "0.10.0", path = "../forge-core" }
tokio = { workspace = true }
sqlx = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
uuid = { workspace = true }
chrono = { workspace = true }
chrono-tz = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
dashmap = { workspace = true }
ahash = { workspace = true }
futures-util = { workspace = true }
tokio-util = { workspace = true }
base64 = { workspace = true }
sha2 = { workspace = true }
subtle = { workspace = true }

# --- Optional deps (gated by feature) ---

# `gateway` feature: HTTP server, JWT auth, OAuth, MCP, webhook signatures,
# and TLS termination on the gateway listener. Bundled together because they
# share the same axum/tower/jsonwebtoken stack and the per-component dep
# savings are negligible compared to the gateway vs no-gateway split.
axum = { workspace = true, optional = true }
ipnet = { workspace = true, optional = true }
tower = { workspace = true, optional = true }
tower-http = { workspace = true, optional = true }
bytes = { workspace = true, optional = true }
jsonwebtoken = { workspace = true, optional = true }
argon2 = { workspace = true, optional = true }
password-hash = { workspace = true, optional = true }
ring = { version = "0.17", optional = true }
serde_urlencoded = { version = "0.7", optional = true }
percent-encoding = { version = "2", optional = true }
aho-corasick = { version = "1", optional = true }
hmac = { version = "0.12", optional = true }
sha1 = { version = "0.10", optional = true }
# Gateway TLS termination: rustls + tls-listener implement axum::serve::Listener.
# Pulled in unconditionally with `gateway`; activated at runtime via
# `[gateway.tls] cert_path + key_path` in forge.toml.
tokio-rustls = { version = "0.26", default-features = false, features = ["ring"], optional = true }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"], optional = true }
tls-listener = { version = "0.11", default-features = false, features = ["rustls-ring", "axum", "tokio-net"], optional = true }
jsonschema = { workspace = true, optional = true }

# `geoip` feature: bundled IP-to-country DB (~10MB) + MaxMind reader.
# Network access is required at compile time to fetch the DB; opt-in only.
db_ip = { version = "0.3", default-features = false, features = ["ipv4", "ipv6", "include-country-code-lite"], optional = true }
maxminddb = { version = "0.28", optional = true }

# `otel` feature: OpenTelemetry exporters (heavy — ~5 OTel crates + protobuf).
opentelemetry = { workspace = true, optional = true }
opentelemetry_sdk = { workspace = true, optional = true }
opentelemetry-otlp = { workspace = true, optional = true }
opentelemetry-semantic-conventions = { workspace = true, optional = true }
opentelemetry-appender-tracing = { workspace = true, optional = true }
tracing-opentelemetry = { workspace = true, optional = true }

[features]
# No defaults — `forgex` is the public entry point and composes feature presets.
default = []

# --- Subsystem features ---

# HTTP gateway bundle: RPC, SSE realtime, OAuth, MCP, webhooks, signals.
# Pulls the entire axum/tower/tower-http stack. Disable for worker-only
# binaries that need no HTTP surface.
gateway = [
    "dep:axum",
    "dep:tower",
    "dep:tower-http",
    "dep:bytes",
    "dep:ipnet",
    "dep:jsonwebtoken",
    "dep:argon2",
    "dep:password-hash",
    "dep:ring",
    "dep:serde_urlencoded",
    "dep:percent-encoding",
    "dep:aho-corasick",
    "dep:hmac",
    "dep:sha1",
    "dep:tokio-rustls",
    "dep:rustls",
    "dep:tls-listener",
    "dep:jsonschema",
]

# Background job queue and worker (PG-backed, SKIP LOCKED).
jobs = []

# Durable workflow executor with versioned signatures. Workflows resume by
# enqueueing jobs onto the queue, so the `jobs` subsystem is required.
workflows = ["jobs"]

# Cron scheduler with leader-only execution. Each tick enqueues a job for
# the worker pool to execute, so the `jobs` subsystem is required.
cron = ["jobs"]

# Long-running daemon runner (singletons, leader-elected).
daemons = []

# OAuth 2.1 + PKCE for MCP authentication. Without this, MCP tools use
# only JWT bearer auth (token passed directly in the request).
mcp-oauth = ["gateway"]

# GeoIP enrichment (sub-feature of `gateway` since signals lives there).
# Bundles a ~10MB IP-to-country database; pulls a build-time download for
# `db_ip`. Skip if you don't run signals or want offline builds.
geoip = ["gateway", "dep:db_ip", "dep:maxminddb"]

# OpenTelemetry trace/metric/log exporters. Disable to skip 5+ OTel crates,
# protobuf stubs, and reqwest-otlp.
otel = [
    "dep:opentelemetry",
    "dep:opentelemetry_sdk",
    "dep:opentelemetry-otlp",
    "dep:opentelemetry-semantic-conventions",
    "dep:opentelemetry-appender-tracing",
    "dep:tracing-opentelemetry",
]

# --- Bundle features (composition shortcuts) ---

# Everything except testcontainers and geoip. What `forgex` activates by default.
# `geoip` is intentionally excluded: it requires a build-time network fetch to
# download the bundled IP-to-country DB. Enable it explicitly with
# `--features forge-runtime/geoip` when you need IP enrichment and have network
# access at build time.
full = [
    "gateway",
    "mcp-oauth",
    "jobs",
    "workflows",
    "cron",
    "daemons",
    "otel",
]

# --- Test infrastructure ---
testcontainers = ["forge-core/testcontainers"]

[dev-dependencies]
tokio-test = { workspace = true }
tempfile = { workspace = true }
# In-memory self-signed cert for the TLS handshake e2e test in gateway/tls.rs.
# `reqwest` (with rustls-tls) is already a regular dep, so the test reuses it.
rcgen = { version = "0.13", default-features = false, features = ["pem", "ring"] }