Choose your integration path
You have read the Quickstart and you know derec-library exists. This page helps you decide how to wire it in. There are four orthogonal choices: API surface, language, role, and storage strategy.
1. Orchestrator or primitives
The library exposes the same protocol at two altitudes. This section is the practical decision; the conceptual treatment lives in Concepts / Primitives and Orchestrator.
Orchestrator — DeRecProtocol
DeRecProtocolThe right default for almost every application. The orchestrator:
tracks per-flow pending state (in-flight sharing rounds, outstanding unpair acks, recovery accumulators);
binds inbound responses to the requests that triggered them;
drives every flow through
start(DeRecFlow::...)/process(&bytes)/accept(action);surfaces typed
DeRecEventvalues your application reacts to.
Pick the orchestrator when the host process is the long-lived owner of a paired-channel set and you want the library to handle state, replay protection, role gating, and event correlation for you.
Primitives — library::primitives::*
library::primitives::*Each flow's stateless produce_* / process_* helpers, exposed under derec_library::primitives::{pairing, sharing, verification, discovery, recovery, unpairing, update_channel_info}. These are the same building blocks the orchestrator composes, made available directly. The library does not track pending state for you — your application owns the shared keys, the in-flight requests, the timeouts, and the role gating.
Pick the primitives when:
the deployment is stateless (each request is handled by a fresh process and there is no in-memory continuity);
you are driving the protocol from a non-Rust environment over the wire format and need bare-metal control of every envelope;
you are integrating into an existing actor / message-queue system that already owns per-flow state.
The primitives skip the role-enforcement and replay-protection guarantees the orchestrator provides. If you choose this path you are responsible for enforcing the protocol invariants (timestamp window, role directionality, nonce binding) yourself — see Concepts → Trust & Threat Model.
2. Language / SDK
The four SDKs are generated from the same Rust source. Functionally they expose the same orchestrator and the same flows; pick by host environment.
Rust
Backend services, CLIs, anything where you want maximum control and the lowest overhead. This is the canonical surface — everything else is generated from it. See the Rust SDK reference.
.NET
Integrating into a .NET application (server, desktop, mobile via .NET MAUI). Same orchestrator-level concepts as Rust, exposed through the C ABI bridge. See the .Net SDK reference.
TypeScript (Node.js)
Server-side JavaScript / TypeScript via @derec-alliance/nodejs. Same concepts as Rust with idiomatic async/await. See the TypeScript SDK reference.
TypeScript (Web)
Browser apps via @derec-alliance/web. Same API as the Node.js package, bundled as a WASM blob. See the TypeScript SDK reference.
Go
Not yet shipped — see Go SDK for status.
3. Role
Every paired channel has a role, fixed at pairing time and enforced by the orchestrator on every subsequent flow. See Overview → Roles for the protocol-level role model (Owner / Helper / Replica) and Concepts / Replicas for the full replica treatment. The short version:
Owner — the device that owns the Secret. Drives
ProtectSecret,VerifyShares,Discovery,RecoverSecret,UpdateChannelInfo, andUnpairagainst paired Helpers, and fans the Secret out to every paired Replica.Helper — stores one share per Secret version. Only ever responds; cannot initiate protocol flows above.
ReplicaSource / ReplicaDestination — the two wire-level roles that appear only during the replica pair handshake. Once the initial Secret sync completes, both sides converge to be operationally equivalent to the Owner and can drive any flow toward the Helpers.
The orchestrator rejects any start(DeRecFlow::...) call that doesn't match this node's role on the targeted channel with Error::RoleMismatch. A single host process can hold different roles on different channels simultaneously — the role is per-channel, not per-process.
4. Storage strategy
The four store traits decouple persistence from the protocol. In practice:
In-memory — fastest path to a working prototype; what the tests in
bindings/rust/src/protocol.rsuse. Lose-on-restart but ideal for development.SQLite — single-process apps, mobile, edge. Reference implementation at
bindings/sqlite/.Postgres — multi-process or server-side deployments. Reference implementation at
bindings/postgres/.Custom — anything that satisfies the four trait contracts is fair game. Copy one of the reference implementations as a starting point — the trait method signatures are stable and the contracts are documented inline.
The store traits are async-shaped but executor-agnostic. Sync backends (in-memory HashMap, embedded SQLite) return Box::pin(std::future::ready(...)) at zero cost. Async backends (Postgres pool, network-attached KV) return Box::pin(async move { ... }).
Decision flowchart
Once you've made these four calls, the Minimal integration example shows the resulting wiring end-to-end.
Last updated