README.md (10868B)
1 # radroots_sdk 2 3 `radroots_sdk` is the host-neutral asynchronous client engine for Radroots. 4 It composes the canonical event, trade, signing, transport, storage, and sync 5 crates without installing a runtime, starting workers, opening files, probing 6 the network, selecting an account, or choosing fallback transports. 7 8 The crate root intentionally exports only `Client`, `ClientBuilder`, `Error`, 9 and `Result`. Advanced operations live in the `farm`, `listing`, `trade`, 10 `signing`, `transport`, `storage`, `sync`, `diagnostics`, and `capability` 11 modules. 12 13 The package charter is the normative [`radroots_sdk` crate 14 specification](../../contracts/crates/release_v1/radroots_crates_release_v1.toml). 15 This advanced front door is intended for CLI, Studio, FFI/mobile, and native 16 applications that need to compose storage, signing, transport, or sync 17 capabilities directly. Ordinary Rust applications should use the curated 18 `radroots` facade. 19 20 Persistent startup capacity failures use `ErrorKind::StorageSpaceInsufficient` 21 and the existing `storage_space_insufficient` protocol report. Native sources 22 remain available through the error chain; display, debug and protocol reports 23 exclude their paths and diagnostic text. Hosts retain existing stores and 24 reconcile prior effects before retrying. 25 26 ## Getting started 27 28 The default `memory` feature provides an inert, in-process backend. The caller 29 supplies its source generation; building the client creates no files, opens no 30 network connection, installs no runtime, and starts no worker. 31 32 ```rust 33 use radroots_sdk::{ClientBuilder, capability::CapabilityId}; 34 use radroots_storage::event::SourceGeneration; 35 36 let generation = SourceGeneration::new([1; 32])?; 37 let client = ClientBuilder::memory(generation).build()?; 38 let storage = client 39 .capabilities() 40 .get(CapabilityId::CANONICAL_STORAGE); 41 assert!(storage.is_some()); 42 43 # Ok::<(), Box<dyn std::error::Error>>(()) 44 ``` 45 46 The complete executable form, including explicit asynchronous shutdown, lives 47 in [`examples/safe_memory_client.rs`](examples/safe_memory_client.rs). The 48 side-effect-free transport-selection example lives in 49 [`examples/transport_profile.rs`](examples/transport_profile.rs). 50 51 ## Feature contract 52 53 The complete public feature vocabulary is: 54 55 | Feature | Capability | 56 | --- | --- | 57 | `memory` | deterministic in-process reference storage; the default feature | 58 | `sqlite` | explicit canonical SQLite storage construction | 59 | `sync` | composition with a caller-supplied canonical sync engine | 60 | `nostr` | Nostr conversion and concrete source/sink adapters; implies `sync` | 61 | `nip46` | NIP-46 signer provider; implies `nostr` | 62 | `local-signing` | explicit local signing and secret-provider adapters | 63 | `radrootsd` | explicitly invoked private daemon execution adapter; implies `sync` | 64 | `geonames` | concrete GeoNames provider integration | 65 | `knowledge` | deterministic knowledge event contracts/codecs | 66 | `native` | `sqlite`, `sync`, and `local-signing` | 67 | `full` | every supported production capability | 68 69 There are no `runtime`, `local-runtime`, `signer-adapters`, 70 `transport-nostr-runtime`, `transport-nostr-client`, or fixture features. 71 Features compile capabilities; they do not perform I/O. Optional dependencies 72 are activated only by their owning feature. 73 74 The supported qualification matrix is: 75 76 ```sh 77 cargo check -p radroots_sdk --lib --no-default-features 78 cargo check -p radroots_sdk --all-targets 79 cargo check -p radroots_sdk --lib --no-default-features --features memory 80 cargo check -p radroots_sdk --lib --no-default-features --features sqlite 81 cargo check -p radroots_sdk --lib --no-default-features --features sync 82 cargo check -p radroots_sdk --lib --no-default-features --features blossom 83 cargo check -p radroots_sdk --lib --no-default-features --features nostr 84 cargo check -p radroots_sdk --lib --no-default-features --features nip46 85 cargo check -p radroots_sdk --lib --no-default-features --features local-signing 86 cargo check -p radroots_sdk --lib --no-default-features --features radrootsd 87 cargo check -p radroots_sdk --lib --no-default-features --features geonames 88 cargo check -p radroots_sdk --lib --no-default-features --features knowledge 89 cargo check -p radroots_sdk --lib --no-default-features --features native 90 cargo check -p radroots_sdk --lib --no-default-features --features full 91 cargo check -p radroots_sdk --all-targets --all-features 92 ``` 93 94 ## Explicit composition 95 96 `ClientBuilder` requires a storage capability. `ClientBuilder::memory(...)` 97 and `ClientBuilder::sqlite(...)` are explicit constructors; merely enabling a 98 feature or constructing an empty builder creates no resource. Signers, event 99 sources, event sinks, and the sync engine are injected separately. 100 101 `client.storage_operations()` exposes actual owner backup capture, verification, 102 and finalization through the existing storage SPI. SQLite requires an explicit 103 host-owned backup root in its open options. Unsupported backends refuse these 104 operations even if they support reliability metadata. Related application 105 state, identity binding, media leases, and export consent remain host concerns; 106 these operations expose no paths and do not create an application-wide snapshot 107 transaction. Failed capture may retain staging for explicit reconciliation. 108 109 Before inventory and capture, hosts exclude new writes and await 110 `settle_backup_writes()` to drain earlier owner work, including operations whose 111 caller was cancelled. Keep that host exclusion until capture completes; the 112 settling call does not grant a continuing reservation or stop new commands. 113 114 `storage_operations().stage_restore(plan)` verifies and stages a retained 115 snapshot without replacing live state. `finalize_restore(plan)` delegates 116 verification, close and installation to the same owner. These operations 117 return bounded `RestoreCapabilityError` values, never paths or handles. 118 Unsupported backends fail closed. After an installation attempt, explicitly 119 close and reopen before inspecting restored state. Canceling finalization does 120 not release the writer early: explicit close must still drain both pools. 121 The host must preserve a durable delivery guard and reconcile historical IDs 122 and remote outcomes; a restored snapshot never authorizes automatic resend. 123 124 Native mobile hosts can retain one client while changing host-owned identity 125 and relay selection. The host injects one opaque implementation of the 126 canonical `radroots_signing::Signer` SPI; the SDK has no mutable secret slot and 127 accepts no secret string. `transport::NostrSlot` validates a complete relay set 128 before atomically installing it. `ClientBuilder::host_sync(sync::HostPolicy)` 129 explicitly opts SDK-created memory or SQLite storage into system-clock and 130 random operation-ID policy without creating a runtime, timer, retry loop, or 131 worker. 132 133 `Client::signing()` exposes focused operations over that opaque signer. Every 134 returned event is independently rebound to the exact request, expected public 135 key, caller-observed deadline, cancellation signal, event ID, fields, and 136 signature. The `blossom` feature adds a domain-separated BUD-11 upload plan and 137 canonical HTTP authorization header; this credential type cannot enter the 138 relay push API and is never persisted by the SDK. Durable authored relay work 139 continues through the canonical sync operations. Host UI lifecycle code owns 140 polling, background policy, native key custody, and explicit retry. 141 142 Transport profiles are explicit. `Profile::local_only()` contains no target. 143 `Profile::delivery(...)` retains the exact canonical target set and 144 satisfaction policy. Preview transports report unavailable and never 145 substitute Nostr, daemon, local persistence, or another route. 146 147 Farm, listing, and trade preparation is deterministic and side-effect-free. 148 Commit operations accept native operation and idempotency identities, 149 cancellation policy, and an explicit transport profile, then return the 150 canonical sync receipt. Repeating the same idempotent request is the supported 151 resume/replay path. 152 153 Preparation has no commit point. During commit, durable local acceptance is 154 the first commit point; a cancellation observed before that point returns 155 without claiming acceptance. Cancellation after durable acceptance cannot 156 roll the accepted event back: the returned error/receipt identifies the safe 157 resume path, and retrying with the same idempotency identity must not create a 158 second logical operation. Dropping `Client::close` before completion leaves 159 the shared client in a retry-required closing state; call `close` again. 160 161 The SDK does not define a second wire model. Canonical lower-crate domain and 162 protocol types own serialization, validation, versioning, and size limits. 163 SDK request, plan, and receipt structs are constructor-led orchestration types; 164 their private representation is not a persistence or interchange format. 165 166 ## Reliability and privacy 167 168 Backup, restore, integrity, and status operations delegate to 169 `radroots_storage::StorageReliability` and return its native versioned plans, 170 manifests, revisions, stages, and status values. Restore is staged and must be 171 explicitly finalized. Client shutdown is explicit and asynchronous. 172 173 Public farm/listing events contain only the coarse locality represented by the 174 canonical event model. Exact coordinates, private trade terms, protected 175 content, and key references remain behind the private-artifact and secrets 176 SPIs. Diagnostics contain only capability and canonical storage status. Public 177 errors and daemon failures use stable, redacted classifications while retaining 178 private source chains for local diagnostics. 179 180 Signer material and bearer credentials are caller-owned capabilities. The SDK 181 does not read a keyring, accept or generate secret strings, persist secrets, or 182 include credentials in `Debug`, `Display`, diagnostics, receipts, or public 183 error text. A concrete local adapter may be composed explicitly outside the 184 mobile surface, but its key remains opaque. Hosts remain responsible for 185 native custody and for protecting source chains and lower-level logs they 186 choose to expose. 187 188 ## Daemon execution 189 190 The `radrootsd` feature compiles a private HTTP/RPC adapter using the versioned 191 `radroots_protocol::radrootsd::transport_publish::v5` contract. Constructing 192 `transport::DaemonDelivery` is inert. Network contact occurs only when the host 193 invokes `deliver`; bearer credentials are redacted, HTTP error bodies are not 194 surfaced, and the response must match the signed event and requested policies. 195 196 ## Release posture 197 198 This package is enabled for package-realistic validation only. Actual crates.io 199 publication remains blocked pending the approval packet and a separately 200 authorized operator step. The crate is licensed under `MIT OR Apache-2.0`. 201 202 The reviewed all-features public API baseline is recorded at 203 [`contracts/api_baselines/radroots_sdk.txt`](../../contracts/api_baselines/radroots_sdk.txt).