feltdb-client 0.5.0

Native async Rust client for a FeltDB server: records, atomic and idempotent transactions, compare-and-set, bounded queries, read-basis fences, events, and the canonical application API
Documentation

feltdb-client

A native async Rust client for a FeltDB server: the Rust counterpart of @feltdb/core's server runtime. It holds no state of its own; the server is the authority for every read and write.

[dependencies]
feltdb-client = "0.2"
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
use feltdb_client::{Client, Operation, Precondition, Transaction};
use serde_json::json;

#[tokio::main]
async fn main() -> feltdb_client::Result<()> {
    let client = Client::builder("http://127.0.0.1:7700")
        .token(std::env::var("FELTDB_TOKEN").unwrap_or_default())
        .build()?;

    // One atomic commit. The id makes a retry after an uncertain outcome safe.
    let tx = Transaction::new("ship-o-1")
        .operation(Operation::put("orders", "o-1", json!({ "status": "shipped" })).expect_version(1))
        .operation(Operation::create("audit", "a-1", json!({ "order": "o-1" })))
        .precondition(Precondition::absent("locks", "o-1"));
    match client.commit(&tx).await {
        Ok(receipt) => println!("committed at revision {}", receipt.commit_revision),
        Err(error) if error.is_conflict() => println!("lost a race: {:?}", error.precondition_failure()),
        Err(error) if error.is_outcome_unknown() => { /* resubmit `tx` unchanged */ }
        Err(error) => return Err(error),
    }
    Ok(())
}

What it covers

Server surface Client
Records: GET/POST /collections/…, PATCH, DELETE get, list, create, update, delete
Atomic, idempotent transactions with preconditions and fences: POST /transactions commit with Transaction, Operation, Precondition
Read bases: POST /transactions/read-basis read_basis, then Transaction::fence
Compare-and-set: POST /collections/{c}/{id}/cas compare_and_set → CasOutcome
Bounded query: POST /query query with BoundedQuery
Committed revision: GET /revision revision
Live events: GET /events (SSE) events → EventStream
Canonical application API under /v1 client.application(id): discover, query, commit (per-operation if_version via update_if_version/delete_if_version), read_basis, events, replay, provenance, sign_in/sign_up/session/sign_out
Committed state version: GET /v1/state/version application.state_version()
Control plane: /api/tenants, /api/applications/… drafts, revisions, promotion; POST /admin/backups client.control(): create_tenant, create_application, create_draft, update_draft, validate_draft, commit_draft, revision, promote, backup
Health: GET /health health
Capability discovery capabilities
Anything else request(Method, path, body)

Errors carry the server's stable code, its request_id, and for a refused transaction the structured PreconditionFailure. The canonical query and transaction documents are feltdb's own types (re-exported under feltdb_client::wire), so the client and server serialize the same structs.

A server behind a private CA is trusted with Client::builder(url).add_root_certificate_pem(pem), in addition to the bundled public roots; verification is never disabled.

The event stream does not reconnect by itself; reopen it from EventStream::last_event_id(). For an embedded store in your own process, use the feltdb crate instead; to run the server, cargo install feltdb-server.

License: MIT.