For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

The 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 DeRecEvent values 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::*

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.

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.

Language
When to pick it

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, and Unpair against 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.rs use. 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