Async Rust client for EventDBX. The library wraps the Cap'n Proto wire protocol exposed by EventDBX so applications can programmatically list aggregates and events, append or patch data, select subsets of fields, toggle archive status, and verify Merkle roots.
- Tokio-based TCP client with automatic hello handshake and per-request timeouts.
- Noise transport security is on by default; call
with_noise(false)to request plaintext for tests. - High-level APIs for list/get/select aggregate queries, list events, append/create/patch events, archive toggling, and Merkle verification.
- Mutation builders support notes, metadata, and publish targets to direct jobs to specific plugins.
- Reusable
ClientConfigso multiple clients can share the same runtime settings.
- Rust 1.75+ (edition 2024) with Cargo.
- Access to an EventDBX control server endpoint and credentials (token + tenant).
- The Cap'n Proto schema lives in
proto/control.capnp; the build script compiles it automatically, so no manualcapnp compileinvocation is needed.
cargo buildRunning cargo check is usually faster for edit/compile cycles:
cargo checkuse eventdbx_client::{
AppendEventRequest, ClientConfig, EventDbxClient, ListAggregatesOptions, PatchEventRequest,
PublishTarget,
};
use serde_json::json;
#[tokio::main]
async fn main() -> eventdbx_client::Result<()> {
let config = ClientConfig::new("127.0.0.1", "<token>")
.with_tenant("tenant-123") // custom tenant
.with_port(7000); // custom port, 6363; call `.with_noise(false)` to request plaintext
let client = EventDbxClient::connect(config).await?;
// list aggregates
let aggregates = client
.list_aggregates(ListAggregatesOptions::default())
.await?;
println!("Aggregates: {}", aggregates.aggregates);
// append a new event
let append = AppendEventRequest::new(
"person",
"p-110",
"person_status_updated",
json!({ "status": "active" }),
);
append
.publish_targets
.push(PublishTarget::new("search-indexer").with_mode("event-only"));
client.append_event(append).await?;
// patch an existing event with JSON Patch semantics
let patch = PatchEventRequest::new(
"person",
"p-110",
"person_status_updated",
json!([{ "op": "replace", "path": "/status", "value": "inactive" }]),
);
client.patch_event(patch).await?;
Ok(())
}See src/main.rs for dbxtest-cli, a small binary that can exercise individual API calls.
Configure it via environment variables (or pass --host/--port/--token/--tenant):
EVENTDBX_HOST(required)EVENTDBX_PORT(optional, defaults to6363)EVENTDBX_TOKEN(required)EVENTDBX_TENANT(optional, defaults to"default")
Available commands mirror the client surface area: list, select, get, events, append,
patch, create, archive, and verify. Any argument you omit is filled with synthetic data
generated via the fake crate, which makes it easy to sanity-check serialization. Examples:
cargo run list --take 5
cargo run append --aggregate-type person --aggregate-id p-1 \
--event-type person_created --payload '{"status":"active"}'
cargo run verify --aggregate-type person --aggregate-id p-1- Modify
proto/control.capnp. - Run
cargo build(orcargo check). The build script scansproto/and regeneratescontrol_capnp.rsinsideOUT_DIR. - Re-run tests or your application.
cargo testNo integration tests are checked in yet, but the command validates the build and runs any
future unit tests. Combine with cargo fmt --check in CI to ensure formatting.
- Run
cargo fmt&cargo clippy --all-targetsbefore submitting patches. - Ensure any schema changes are reflected in
proto/control.capnpand the corresponding client/type definitions. - Document new APIs in this README or Rustdoc comments where appropriate.