udb 0.4.21

Universal Data Broker — a Rust gRPC broker over multiple databases (Postgres, MySQL, SQLite, MongoDB, ClickHouse, Cassandra, MSSQL, Redis, Qdrant, S3, Neo4j, …) with per-tenant RLS, 2PC, sagas, and CDC.
Documentation
# Workspace hosts the main `udb` crate and the `udb-portable` sub-crate.
# The portable crate uses #[path] includes from `src/` so there is a single
# source of truth for the AST, lexer, checksum, and source-based parser.
# See crates/udb-portable/Cargo.toml.
[workspace]
members = ["crates/udb-portable", "crates/udb-wasm"]
resolver = "2"

[package]
name = "udb"
version = "0.4.21"
edition = "2024"
rust-version = "1.85"
description = "Universal Data Broker — a Rust gRPC broker over multiple databases (Postgres, MySQL, SQLite, MongoDB, ClickHouse, Cassandra, MSSQL, Redis, Qdrant, S3, Neo4j, …) with per-tenant RLS, 2PC, sagas, and CDC."
license = "MIT"
repository = "https://github.com/fahara02/udb"
homepage = "https://github.com/fahara02/udb"
documentation = "https://docs.rs/udb"
readme = "README.md"
keywords = ["grpc", "database", "multi-tenant", "broker", "cdc"]
categories = ["database", "network-programming", "web-programming::http-server"]
authors = ["fahara02 <idea3d.faruk@gmail.com>"]
# Keep the crates.io package below the 10MiB upload cap. Release workflows test
# the full repository before publishing; the package itself only needs the Rust
# crate, embedded proto contract, third-party proto imports, and files referenced
# at compile time.
include = [
    "/Cargo.lock",
    "/Cargo.toml",
    "/LICENSE",
    "/README.md",
    "/build.rs",
    "/docs/abac_seed.json",
    "/docs/generated/contract-baseline.bin",
    "/docs/generated/udb-native-contract.json",
    "/proto/udb/**",
    "/sdk-templates/**",
    "/src/**",
    "/third_party/googleapis/**",
]

[lib]
name = "udb"
path = "src/lib.rs"

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

[features]
# Per-backend feature gating. `default` enables every backend, so the normal
# build, binary, and full test suite include the complete broker surface.
# Each backend can be turned off individually; a slim broker is built with e.g.
# `--no-default-features --features postgres`. When a backend is disabled its
# code/deps are compiled out, and any gRPC-contract RPC it owns (e.g. VectorSearch
# for qdrant, the object RPCs for s3) stays present but returns FailedPrecondition.
# Postgres is the always-on core (sqlx is never gated).
default = ["postgres", "mysql", "sqlite", "qdrant", "s3", "mongodb-native", "neo4j", "clickhouse", "redis", "elasticsearch", "memcached", "mssql", "weaviate", "pinecone", "cassandra", "azureblob", "gcs", "kafka", "otel", "runtime-logging", "http-client", "simd-codecs", "simd-checksum"]
# D.2: exposes `udb::bench_internals` — `#[doc(hidden)]` pub wrappers over hot
# `pub(crate)` functions so Criterion micro-benches (`benches/hotpath_bench.rs`)
# can measure them without widening the public API. NOT a stable API; off by
# default, enabled only for `cargo bench --features bench-internals`.
bench-internals = []
postgres = []
# MySQL and SQLite are optional SQL backends. Each pulls its sqlx driver and is
# enabled by `default`; slim postgres-only builds skip both.
mysql = ["sqlx/mysql"]
sqlite = ["sqlx/sqlite"]
# HTTP-using backends depend on `http-client`, so postgres-only builds do not
# pull reqwest. Adding an HTTP backend automatically enables the shared client.
qdrant = ["http-client"]
mongodb = ["http-client"]
mongodb-native = ["mongodb", "dep:mongodb-driver"]
neo4j = ["http-client"]
clickhouse = ["http-client"]
# Elasticsearch backend over the REST Query DSL.
elasticsearch = ["http-client"]
# Memcached cache backend via the `memcache` crate.
memcached = ["dep:memcache"]
# Microsoft SQL Server backend via the `tiberius` TDS driver.
mssql = ["dep:tiberius", "dep:tokio-util"]
# Weaviate vector backend over the REST API.
weaviate = ["http-client"]
# Pinecone vector backend over the REST API.
pinecone = ["http-client"]
# Cassandra/Scylla wide-column backend via the `scylla` driver.
cassandra = ["dep:scylla"]
# Azure Blob Storage object backend.
azureblob = ["dep:azure_storage", "dep:azure_storage_blobs", "dep:azure_core"]
# Google Cloud Storage object backend.
gcs = ["dep:google-cloud-storage"]
s3 = ["dep:aws-config", "dep:aws-sdk-s3"]
# Master-plan 3.4 KMS extension point: the `KeyProvider` trait + selector ship now
# (env path is the default), but the concrete `AwsKmsProvider` and its `aws-sdk-kms`
# dependency are deferred (see the KMS note in `authn/key_provider.rs`). To activate
# on a networked build: add `aws-sdk-kms = { version = "1", optional = true }` below,
# re-add `kms = ["dep:aws-sdk-kms", "dep:aws-config"]` here, restore the
# `AwsKmsProvider` impl, and commit the updated `Cargo.lock`. The dep is omitted now
# because it cannot be vendored offline (it would break every offline `cargo` resolve).
redis = ["dep:redis"]
# CDC (kafka) uses Redis for publish idempotency and the HTTP client for
# optional schema-registry validation, so it pulls both features. It also
# pulls the vendored `postgres-replication` module's direct deps —
# byteorder/memchr/pin-project-lite/futures-util plus the upstream
# postgres-protocol + postgres-types crates whose APIs the WAL decoder
# consumes. These are wrapped here so the slim postgres-only build does
# not drag them in.
kafka = [
    "dep:rdkafka",
    "redis",
    "http-client",
    "dep:byteorder",
    "dep:memchr",
    "dep:pin-project-lite",
    "dep:futures-util",
    "dep:postgres-protocol",
    "dep:postgres-types",
]
otel = ["dep:opentelemetry", "dep:opentelemetry-otlp", "dep:opentelemetry_sdk", "dep:tracing-opentelemetry", "runtime-logging"]
runtime-logging = ["dep:tracing-subscriber"]
# Shared HTTP client used by REST-backed integrations.
http-client = ["dep:reqwest"]
# ── OFF-by-default optional integrations (not in `default`). ──────────────────
# OpenID Connect discovery / token verification for the auth plane.
oidc = ["dep:openidconnect", "openidconnect/reqwest-blocking", "openidconnect/rustls-tls"]
# WebAuthn / FIDO2 second-factor registration + assertion.
webauthn = [
    "dep:webauthn-rs",
    "dep:openssl",
    "dep:openssl-sys",
    "dep:p256",
    "webauthn-rs/attestation",
    "webauthn-rs/danger-allow-state-serialisation",
]
# Embedded WebRTC SFU media-plane scaffolding. Off by default: Layer A
# signaling/TURN stays available without pulling the media stack.
webrtc = ["dep:webrtc-rs"]
# Pluggable ws:// signalling bridge. A WebSocket server speaking external
# real-time signalling protocols (engines/clients that can't use gRPC), with a
# `SignalingProtocol` trait so more protocols are added as trait impls. The first
# protocol is Unreal Pixel Streaming. Off by default; enabled per deployment and
# activated at runtime by setting `UDB_WS_SIGNALLING_ADDR`.
ws-signalling = ["dep:tokio-tungstenite", "dep:futures-util"]
# Asset image processing (THUMBNAIL/RESIZE steps) via the pure-Rust `image`
# crate. Off by default; no native deps. (Video TRANSCODE/CAPTION would need a
# separate ffmpeg-backed feature + libav, which is not available on all hosts.)
asset-image = ["dep:image"]
# SIMD-accelerated base64 codec for hot wire-encode paths.
simd-codecs = ["dep:base64-simd"]
# SIMD JSON parser for high-throughput JSON decode.
simd-json = ["dep:simd-json"]
# SIMD-accelerated CRC32 checksum (e.g. CDC / object integrity).
simd-checksum = ["dep:crc32fast"]
# Full-screen terminal wizard for `udb init`.
tui = ["dep:ratatui", "dep:crossterm"]
# Line-mode prompt fallback for `udb init --no-tui`.
init-prompts = ["dep:inquire"]

[dependencies]
async-stream = "0.3"
async-trait = "0.1"
aead = "0.5"
aws-config = { version = "1", optional = true }
aws-sdk-s3 = { version = "1", optional = true }
aes-gcm-siv = "0.11"
base64 = "0.22"
bytes = "1"
ed25519-dalek = "2.2.0"
casbin = "2"
chrono = { version = "0.4", features = ["serde"] }
opentelemetry = { version = "0.27", optional = true }
opentelemetry-otlp = { version = "0.27", optional = true }
# OTLP exporter + tracer-provider builder (gated by `otel`). Pinned to the same
# 0.27 line as `opentelemetry`/`opentelemetry-otlp`; the OTLP crate already pulls
# it transitively, declared here so `init_otel` can name it directly.
opentelemetry_sdk = { version = "0.27", features = ["rt-tokio"], optional = true }
include_dir = "0.7"
prometheus = "0.13"
prost = "0.13"
prost-types = "0.13"
rcgen = "0.13"
rdkafka = { version = "0.36", default-features = false, features = ["cmake-build", "tokio", "curl-static"], optional = true }
redis = { version = "0.27", features = ["tokio-comp"], optional = true }
mongodb-driver = { package = "mongodb", version = "3.7", optional = true }
# Memcached binary-protocol client. The sync API is wrapped in
# `tokio::task::spawn_blocking` by the executor so the async runtime does not
# block. `default-features = false` avoids pulling native TLS/OpenSSL.
memcache = { version = "0.17", default-features = false, optional = true }
# Microsoft SQL Server driver over TDS. Default features are disabled to avoid
# the driver's chrono shim; enable the SQL Server 2008+ wire format and rustls.
tiberius = { version = "0.12", default-features = false, features = ["tds73", "rustls"], optional = true }
tokio-util = { version = "0.7", features = ["compat"], optional = true }
# WebSocket server for the pluggable ws:// signalling bridge (feature
# `ws-signalling`). Plain ws:// only (no TLS feature pulled); TLS is terminated
# upstream by nginx/envoy in the documented deployments.
tokio-tungstenite = { version = "0.24", optional = true }
# Pure-Rust image decode/encode/resize for the asset service's THUMBNAIL/RESIZE
# steps (feature `asset-image`). default-features off to pull only PNG/JPEG codecs.
image = { version = "0.25", default-features = false, features = ["png", "jpeg"], optional = true }
# Cassandra / ScyllaDB driver over the CQL binary protocol. Default features
# stay off to avoid unused metrics and cloud-bundle dependencies.
scylla = { version = "0.13", default-features = false, optional = true }
# Azure Blob Storage SDK split across core primitives, storage account support,
# and the blob client.
azure_core = { version = "0.21", default-features = false, optional = true }
azure_storage = { version = "0.21", default-features = false, optional = true }
azure_storage_blobs = { version = "0.21", default-features = false, optional = true }
# Google Cloud Storage client with rustls TLS.
google-cloud-storage = { version = "0.22", default-features = false, features = ["rustls-tls", "auth"], optional = true }
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "blocking"], optional = true }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
toml = "0.8"
toml_edit = "0.22"
statig = { version = "0.4", features = ["macro"] }
ratatui = { version = "0.30", optional = true, default-features = false, features = ["crossterm"] }
crossterm = { version = "0.29", optional = true }
inquire = { version = "0.9", optional = true, default-features = false, features = ["crossterm"] }
sha2 = "0.10"
# SHA-1 is required only for RFC 6238 TOTP (the de-facto authenticator-app HMAC)
# and legacy SAML RSA-SHA1 signature verification. (No `oid` feature needed: the
# SAML verify path prepends the DigestInfo prefix itself — see idp/saml.rs.)
sha1 = "0.10"
# Argon2id password KDF for native password storage (replaces keyed-HMAC).
argon2 = "0.5"
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio-rustls", "postgres", "json", "uuid", "chrono"] }
# rustls 0.23 needs a process-level CryptoProvider installed before the first
# TLS config is built. The dep graph links BOTH aws-lc-rs and ring transitively
# (tonic tls, sqlx, reqwest, tiberius, google-cloud-storage), so rustls cannot
# auto-select and panics on the serve path. We standardise on aws-lc-rs and
# install it explicitly at startup (see install_default_crypto_provider). NOTE:
# sqlx-postgres TLS does NOT use this process-default — it builds its own config
# with builder_with_provider(ring) (runtime-tokio-rustls -> tls-rustls-ring).
# (A build-probe confirmed the Neon/SNI handshake succeeds on both the 22.04 and
# 24.04 toolchains, so this provider choice is NOT a Postgres-connectivity risk.)
rustls = { version = "0.23", features = ["aws_lc_rs"] }
futures = { version = "0.3", default-features = false, features = ["std"] }
tokio = { version = "1", features = ["full"] }
tokio-postgres = { version = "0.7", features = ["with-chrono-0_4", "with-uuid-1", "with-serde_json-1", "runtime"] }
tokio-stream = "0.1"
# Dependencies of the vendored `postgres-replication` module
# (`src/runtime/cdc/postgres_replication/`). Pulled only when the
# `kafka` feature is on; the slim postgres-only build skips them.
byteorder = { version = "1.5", optional = true }
memchr = { version = "2.7", optional = true }
pin-project-lite = { version = "0.2", optional = true }
futures-util = { version = "0.3", default-features = false, features = ["std", "sink"], optional = true }
postgres-protocol = { version = "0.6", optional = true }
postgres-types = { version = "0.2", optional = true }
tonic = { version = "0.12", features = ["tls"] }
tonic-health = "0.12"
tonic-reflection = "0.12"
tower = { version = "0.4", features = ["timeout", "limit"] }
tracing = "0.1"
tracing-opentelemetry = { version = "0.28", optional = true }
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"], optional = true }
uuid = { version = "1", features = ["serde", "v4"] }
wildmatch = "2.3"
x509-parser = "0.16"
jsonwebtoken = "9"
# SAML 2.0 (Phase J): pure-Rust XML reader for metadata/assertion parsing and
# DEFLATE for the HTTP-Redirect AuthnRequest encoding. No native deps; assertion
# signature verification uses the existing `rsa`/`sha2`/`sha1`/`x509-parser`
# stack (see src/runtime/service/auth_service/idp/saml.rs).
quick-xml = "0.31"
flate2 = "1"
# Pure-Rust RSA (already in the tree transitively) — used to publish a JWK Set
# for verifying UDB-issued RS256 tokens (authn GetJwks).
rsa = { version = "0.9", features = ["pem"] }
dotenvy = "0.15"
arc-swap = "1.9.1"
urlencoding = "2"
# ── OFF-by-default optional integrations. Each is pulled in ONLY by its named
# feature (see [features] above); none are in `default`. ──────────────────────
# OpenID Connect client (discovery + ID-token verification). Gated by `oidc`.
# TODO(parent): verify version — 4.x is the current major on crates.io; if the
# resolver objects, pin to a known-good 3.x ("3").
openidconnect = { version = "4", default-features = false, optional = true }
# WebAuthn / FIDO2 server-side ceremony. Gated by `webauthn`.
# TODO(parent): verify version — 0.5 is the latest 0.x major on crates.io.
webauthn-rs = { version = "0.5", optional = true }
# webauthn-rs 0.5 uses openssl internally. Vendoring keeps the feature build
# portable on Windows/MSVC, matching the repo's general "no system OpenSSL"
# stance for optional integrations.
openssl = { version = "0.10", features = ["vendored"], optional = true }
openssl-sys = { version = "0.9", features = ["vendored"], optional = true }
# Q#9-11 dev-only WebAuthn software authenticator (UDB_WEBAUTHN_TEST_MODE): a real
# P-256 keypair produces a genuine "none"-attestation credential + ES256 assertion
# that webauthn-rs verifies legitimately (NOT an accept-any bypass). Gated by `webauthn`.
p256 = { version = "0.13", features = ["ecdsa"], optional = true }
# SIMD base64 codec. Gated by `simd-codecs`.
# TODO(parent): verify version — 0.8 is the latest on crates.io.
base64-simd = { version = "0.8", optional = true }
# SIMD JSON parser. Gated by `simd-json`.
# TODO(parent): verify version — confirm latest 0.x major on crates.io.
simd-json = { version = "0.14", optional = true }
# SIMD-accelerated CRC32. Gated by `simd-checksum`.
crc32fast = { version = "1", optional = true }
# webrtc-rs media stack. Aliased so it does not collide with generated
# `udb.core.webrtc` protocol modules or the `webrtc` Cargo feature name.
webrtc-rs = { package = "webrtc", version = "0.8", optional = true }

[build-dependencies]
protoc-bin-vendored = "3"
tonic-build = "0.12"
# Match prost-build's identifier casing (proto message name -> Rust type name)
# in the §7 DTO-redaction codegen, so generated impl paths resolve exactly.
heck = "0.5"

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
# D.2 heap-allocation profiling for the hot paths (run the dhat_hotpath example).
dhat = "0.3"
redis = { version = "0.27", features = ["tokio-comp"] }
rdkafka = { version = "0.36", default-features = false, features = ["cmake-build", "tokio", "curl-static"] }
aws-config = "1"
aws-sdk-s3 = "1"
chrono = { version = "0.4", features = ["serde"] }
# `test-util` enables `start_paused`/`tokio::time::advance` for deterministic
# time-based unit tests (e.g. the Phase-9 control-plane push debouncer).
tokio = { version = "1", features = ["full", "test-util"] }
uuid = { version = "1", features = ["serde", "v4"] }
serde_json = "1"
# Parity between this crate and `udb-portable` is structural: both crates
# include the same source files (`schema/ast.rs`, `schema/checksum.rs`,
# `parser/*.rs`) via `#[path]` inside `crates/udb-portable/src/lib.rs`.
# The portable crate's own tests (`cargo test -p udb-portable`) pin checksum
# determinism, AST round-trip, and parser smoke behavior.

[[bench]]
name = "core_bench"
harness = false

# D.2 hot-path micro-benchmarks. Needs `bench-internals` to reach the
# `pub(crate)` conversion/parse helpers: `cargo bench --features bench-internals --bench hotpath_bench`.
[[bench]]
name = "hotpath_bench"
harness = false
required-features = ["bench-internals"]

# D.2 END-TO-END perf against the live docker backends (relational + object):
# `UDB_BENCH_LIVE=1 cargo bench --features bench-internals --bench live_backends_bench`.
[[bench]]
name = "live_backends_bench"
harness = false
required-features = ["bench-internals"]

# D.2 allocation profile for the same hot paths (dhat heap profiler):
# `cargo run --release --features bench-internals --example dhat_hotpath`.
[[example]]
name = "dhat_hotpath"
required-features = ["bench-internals"]

# ── Build profiles ────────────────────────────────────────────────────────────
# Default `--release` (dev + CI): thin LTO + a single codegen unit capture most of
# the cross-crate-inlining win without fat-LTO's multi-minute link. `panic` stays
# "unwind" ON PURPOSE — the broker isolates per-request/task panics (tonic/tokio)
# and must NOT abort the whole process.
[profile.release]
lto = "thin"
codegen-units = 1

# Benches MUST measure the shipped, optimised path (bench-integrity doctrine), not a
# default-profile build.
[profile.bench]
inherits = "release"

# Maximum-optimisation profile for the SHIPPED release binaries: `release-binaries.yml`
# builds `--profile dist`. Compile time is irrelevant for a tagged release, so go fat
# LTO + 1 codegen unit + symbol strip for the fastest, smallest artifact. Per-target
# `target-cpu` is supplied by the workflow (portable per-OS baselines, never `native`).
[profile.dist]
inherits = "release"
lto = "fat"
strip = "symbols"