[workspace]
members = [
    ".",
    "crates/*",
    "examples/daemon",
    "examples/http",
    "examples/jobs",
]
resolver = "3"

[workspace.package]
version = "0.12.1"
edition = "2024"
license = "MIT"
authors = ["Emil Schütt <emil.schutt@gmail.com>"]
repository = "https://github.com/retrokiller543/overseerd"
homepage = "https://github.com/retrokiller543/overseerd"
keywords = ["daemon", "rpc", "framework", "async", "ioc"]
categories = ["network-programming", "asynchronous"]

[workspace.dependencies]
# Workspace member crates. The `version` is required for publishing: crates.io
# strips the `path` and resolves the dependency by version instead.
overseerd-config = { path = "crates/config", version = "0.12.1" }
overseerd-core = { path = "crates/core", version = "0.12.1" }
overseerd-di = { path = "crates/di", version = "0.12.1" }
overseerd-dirs = { path = "crates/dirs", version = "0.12.1" }
overseerd-hooks = { path = "crates/hooks", version = "0.12.1" }
overseerd-jobs = { path = "crates/jobs", version = "0.12.1" }
overseerd-jobs-macros = { path = "crates/jobs-macros", version = "0.12.1" }
overseerd-app = { path = "crates/app", version = "0.12.1" }
overseerd-client = { path = "crates/client", version = "0.12.1" }
overseerd-rpc = { path = "crates/rpc", version = "0.12.1" }
overseerd-macros = { path = "crates/macros", version = "0.12.1" }
overseerd-macros-core = { path = "crates/macros-core", version = "0.12.1" }
overseerd-rpc-macros = { path = "crates/rpc-macros", version = "0.12.1" }
overseerd-transport = { path = "crates/transport", version = "0.12.1" }
overseerd-axum = { path = "crates/axum", version = "0.12.1" }
overseerd-axum-macros = { path = "crates/axum-macros", version = "0.12.1" }

# Common dependencies
arc-swap = "1.9.1"
bitflags = "2"
# The axum HTTP protocol. No TLS feature is enabled, keeping `openssl`/`rsa` out of the
# dependency tree (project rule); terminate TLS at a reverse proxy instead.
axum = "0.8"
serde_json = "1"
serde_urlencoded = "0.7"
http = "1"
# Base is the wasm-compatible common subset (json only, fetch backend). Native consumers add
# `rustls-tls` + `stream` per-target (see crates/axum). No `openssl` — keeps the banned-crate rule.
reqwest = { version = "0.12", default-features = false, features = ["json"] }
# hyper as a client: the legacy/util client + body helpers. Plain HTTP connector only (no TLS
# feature), keeping openssl/rsa out — terminate TLS at a proxy, or use the reqwest backend.
hyper = { version = "1", features = ["client", "http1"] }
hyper-util = { version = "0.1", features = ["client", "client-legacy", "http1", "tokio"] }
http-body-util = "0.1"
tokio-tungstenite = { version = "0.29", default-features = false, features = ["connect"] }
# Unified native+wasm WebSocket client for the STOMP transport (one API on both targets). No TLS
# feature enabled — all TLS backends are opt-in, so plain `ws://` needs nothing (no openssl, nothing
# for CI to install); terminate TLS at a proxy, or a user enables a `rustls-*` feature themselves.
tokio-tungstenite-wasm = { version = "0.8", default-features = false }
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
# `File`/`Blob` DOM bindings for the wasm client's ergonomic multipart upload builder. wasm-target
# only; features are enabled per-crate. Clean dep tree (wasm-bindgen + js-sys) — no openssl/rsa.
web-sys = "0.3"
# Converts a decoded STOMP message to a `JsValue` for the subscription callback (any `Serialize`,
# in both tsify ABIs). wasm-target only.
serde-wasm-bindgen = "0.6"
# STOMP 1.2 frame grammar (parse + serialize). Deps: either + nom + paste only — no
# openssl/rsa/tokio, keeping the project's banned-crate rule intact. Framing only; the broker,
# serve loop, and client transport are ours.
stomp-parser = "0.8"
# `Cookie` header parsing for `RequestMeta`. Default features off: only the base parser is
# needed, not the signed/private cookie-jar crypto (aes-gcm/hmac/sha2/rand).
cookie = { version = "0.18", default-features = false }
# Optional: a `TopicParam` impl for templated STOMP topics (behind the axum `uuid` feature).
uuid = "1"
bytes = "1"
notify = "6"
thiserror = "2"
toml = "1.1"
serde_yaml_ng = "0.10"
directories = "6"
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1"
tokio-util = "0.7"
tower = { version = "0.5", features = ["util"] }
futures = "0.3"
serde = { version = "1", features = ["derive"] }
postcard = { version = "1", features = ["use-std"] }
async-trait = "0.1"
linkme = "0.3"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "ansi", "json"] }
# Typed wasm<->JS conversion + TypeScript type generation for `#[dto]` types, so the generated
# client's arguments/returns are typed in TS (via `Ts<T>`) rather than `any`. Its derive + `Ts<T>`
# hardcode `::tsify`/`::wasm_bindgen`, so a wasm client crate depends on `tsify` + `wasm-bindgen`
# directly (see the http example). Clean dep tree (serde + wasm-bindgen + gloo-utils) — no
# openssl/rsa. Listed here only to pin the version the docs/examples reference.
tsify = "0.5"
syn = { version = "2", features = ["full"] }
quote = "1"
proc-macro2 = "1"

[package]
name = "overseerd"
description = "An async daemon framework with compile-time dependency injection, typed RPC, and config — the all-in-one facade crate."
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
keywords.workspace = true
categories.workspace = true

[features]
default = ["di-check"]

# Re-export the native RPC daemon through the facade for convenience. The protocol crate owns
# its own macros; the facade just enables its `facade` feature (so its codegen roots at
# `::overseerd::daemon::*`) and re-exports it. Off by default (the facade forces no protocol):
# enable `daemon` for the RPC protocol, or `axum` for HTTP, or both. The daemon also lives in its
# own `overseerd-rpc` crate for a direct dependency.
daemon = ["dep:overseerd-rpc", "overseerd-rpc/facade"]

# Re-export the axum/HTTP protocol through the facade's `axum` module. Independent of `daemon`;
# enable both to host RPC and HTTP side by side.
axum = ["dep:overseerd-axum", "overseerd-axum/facade"]

# The job scheduler (`overseerd::jobs`): `#[job(every = ..)]` / `#[job(cron = ..)]` methods and
# a runtime `JobScheduler::schedule` API, run as supervised background tasks. Protocol-neutral —
# compose it with `daemon` and/or `axum`. Enables the plugin crate's `facade` feature so its
# macros root generated types at `::overseerd::jobs::*`.
jobs = ["dep:overseerd-jobs", "overseerd-jobs/facade"]

# WebSocket controllers for the axum protocol (`#[controller(ws = ..)]`, `register_ws`). Opt-in,
# since WebSockets pull in extra machinery a plain HTTP app does not need. Implies `axum`.
ws = ["axum", "overseerd-axum/ws"]

# STOMP 1.2 pub/sub over WebSocket: the broker, `#[controller(ws = Stomp)]` handlers, `#[topics]`,
# and the typed generated client. Implies `ws`.
stomp = ["ws", "overseerd-axum/stomp"]

# The `multipart/form-data` request extractor (`overseerd::axum::Multipart`), for upload handlers.
# Off by default (mirrors axum); implies `axum`. The client-side `Multipart` body builder is always
# available under `client`.
multipart = ["axum", "overseerd-axum/multipart"]

# Cross-cutting `uuid` integration: light up `uuid` support in whatever crates are enabled, without
# forcing any of them on. The `?/` activations fire only for a crate that is already present — so
# `uuid` composes with `axum`/`stomp`/future protocols rather than pulling them in. Add a new
# crate's uuid integration here as one more `?/uuid` entry.
uuid = ["overseerd-axum?/uuid"]

# Compile the generated client SDK. Protocol-neutral: it turns on the client *surface* of
# whichever protocol(s) are enabled — `client` + `daemon` gives the (self-contained) RPC
# client; `client` + `axum` gives the HTTP client codegen, which needs a backend selected
# below (`reqwest` / `hyper`). The `?` activations fire only for a protocol that is present.
client = [
    "overseerd-rpc?/client",
    "overseerd-axum?/client",
]

# HTTP client backends — independent, so a user picks one (or both). Each implies `client`.
reqwest = ["client", "overseerd-axum?/reqwest"]
hyper = ["client", "overseerd-axum?/hyper"]
tungstenite = ["client", "ws", "overseerd-axum?/tungstenite"]

# Opt into the new `tsify` `Ts<T>` wasm ABI for the generated browser client (typed + leak-free).
# Requires the unreleased `tsify` (git master) as a wasm dep in your crate; off by default uses the
# published `tsify` `into_wasm_abi` path (no git dependency needed).
wasm-ts = ["overseerd-axum?/wasm-ts"]

# Emit compile-time dependency-injection checks (a `Wiring: Provide<Dep>` bound
# per concrete dependency). A missing provider becomes a `cargo check` error.
di-check = [
    "overseerd-macros/di-check",
    "overseerd-di/di-check",
    "overseerd-config/di-check",
    "overseerd-app/di-check",
    "overseerd-rpc?/di-check",
    "overseerd-axum?/di-check",
    "overseerd-jobs?/di-check",
]

# Enable YAML config sources (`application.yaml`) alongside the default TOML.
yaml = ["overseerd-config/yaml", "overseerd-app/yaml", "overseerd-rpc?/yaml", "overseerd-axum?/yaml"]

# Provide the `init_tracing` helper, pulling in `tracing-subscriber`. When the `jobs` scheduler
# is also enabled, this turns on its jobs-aware `init_tracing` (per-run log capture layer) too.
tracing-subscriber = [
    "overseerd-app/tracing-subscriber",
    "overseerd-jobs?/tracing-subscriber",
]

# Watch config files and reload on change (`ConfigManager::watch_config`), via `notify`.
watch = ["overseerd-config/watch", "overseerd-app/watch", "overseerd-rpc?/watch", "overseerd-axum?/watch"]

# Shared across all targets: the client core, the (wasm-safe) transport substrate, the axum
# protocol's *client* surface, and the proc-macros (built for the host regardless of target).
[dependencies]
overseerd-client = { workspace = true }
overseerd-transport = { workspace = true }
overseerd-axum = { workspace = true, optional = true }
# The facade depends only on the *core* macros crate; each protocol crate owns and re-exports
# its own macros (the facade reaches them through the protocol crate).
overseerd-macros = { workspace = true }
futures = { workspace = true }
serde = { workspace = true }

# Native (non-wasm): the daemon stack — DI engine, config/dirs (filesystem), the app runtime,
# hooks, the RPC daemon, and tokio. A browser client needs none of these, and several do not build
# for wasm (linkme, `directories`, `notify`, tokio net), so they are compiled out there.
[target.'cfg(not(target_family = "wasm"))'.dependencies]
overseerd-core = { workspace = true }
overseerd-di = { workspace = true }
overseerd-hooks = { workspace = true }
overseerd-dirs = { workspace = true }
overseerd-config = { workspace = true }
overseerd-app = { workspace = true }
overseerd-rpc = { workspace = true, optional = true }
overseerd-jobs = { workspace = true, optional = true }
tokio = { workspace = true }
postcard = { workspace = true }

[dev-dependencies]
serde_json = { workspace = true }
