commit 03c568672034f9d33e896c9585eaea2362c664d6
parent 9aa7d727eff8cc342fe698f53903e1339772ebf0
Author: triesap <tyson@radroots.org>
Date: Mon, 3 Aug 2026 10:12:14 +0000
sdk: align package manifest and module root
- declare the final required and optional lower package graph
- replace legacy feature aliases with the governed vocabulary
- establish the eleven-module SDK ownership skeleton
- verify default and all-feature package boundaries
Diffstat:
17 files changed, 320 insertions(+), 3296 deletions(-)
diff --git a/.cargo/config.toml b/.cargo/config.toml
@@ -12,6 +12,7 @@ radroots_event = { path = "../lib/crates/event" }
radroots_event_codec = { path = "../lib/crates/event_codec" }
radroots_event_index = { path = "../lib/crates/event_index" }
radroots_geocoder = { path = "../lib/crates/geocoder" }
+radroots_geonames = { path = "../lib/crates/geonames" }
radroots_identity = { path = "../lib/crates/identity" }
radroots_nostr = { path = "../lib/crates/nostr" }
radroots_nostr_connect = { path = "../lib/crates/nostr_connect" }
@@ -23,6 +24,9 @@ radroots_protected_store = { path = "../lib/crates/protected_store" }
radroots_secret_vault = { path = "../lib/crates/secret_vault" }
radroots_secrets = { path = "../lib/crates/secrets" }
radroots_signing = { path = "../lib/crates/signing" }
+radroots_storage = { path = "../lib/crates/storage" }
+radroots_storage_sqlite = { path = "../lib/crates/storage_sqlite" }
+radroots_sync = { path = "../lib/crates/sync" }
radroots_transport = { path = "../lib/crates/transport" }
radroots_transport_nostr = { path = "../lib/crates/transport_nostr" }
radroots_transport_reticulum = { path = "../lib/crates/transport_reticulum" }
diff --git a/Cargo.lock b/Cargo.lock
@@ -30,27 +30,6 @@ dependencies = [
]
[[package]]
-name = "ahash"
-version = "0.8.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
-dependencies = [
- "cfg-if",
- "once_cell",
- "version_check",
- "zerocopy",
-]
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
-dependencies = [
- "memchr",
-]
-
-[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -72,12 +51,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
[[package]]
-name = "arraydeque"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
-
-[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -160,12 +133,6 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64"
-version = "0.21.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
-
-[[package]]
-name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
@@ -215,9 +182,6 @@ name = "bitflags"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
-dependencies = [
- "serde_core",
-]
[[package]]
name = "block-buffer"
@@ -344,60 +308,12 @@ dependencies = [
]
[[package]]
-name = "config"
-version = "0.14.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf"
-dependencies = [
- "async-trait",
- "convert_case",
- "json5",
- "nom",
- "pathdiff",
- "ron",
- "rust-ini",
- "serde",
- "serde_json",
- "toml",
- "yaml-rust2",
-]
-
-[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
-name = "const-random"
-version = "0.1.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
-dependencies = [
- "const-random-macro",
-]
-
-[[package]]
-name = "const-random-macro"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
-dependencies = [
- "getrandom 0.2.17",
- "once_cell",
- "tiny-keccak",
-]
-
-[[package]]
-name = "convert_case"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -437,30 +353,6 @@ dependencies = [
]
[[package]]
-name = "critical-section"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.5.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
name = "crossbeam-queue"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -476,12 +368,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
-name = "crunchy"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
-
-[[package]]
name = "crypto-bigint"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -521,12 +407,6 @@ dependencies = [
]
[[package]]
-name = "deranged"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
-
-[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -549,15 +429,6 @@ dependencies = [
]
[[package]]
-name = "dlv-list"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
-dependencies = [
- "const-random",
-]
-
-[[package]]
name = "dotenvy"
version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -647,27 +518,6 @@ dependencies = [
]
[[package]]
-name = "encoding_rs"
-version = "0.8.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "enum-as-inner"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -695,6 +545,18 @@ dependencies = [
]
[[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
+[[package]]
name = "fastrand"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -769,6 +631,16 @@ dependencies = [
]
[[package]]
+name = "fs2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
name = "futures"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -776,7 +648,6 @@ checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
- "futures-executor",
"futures-io",
"futures-sink",
"futures-task",
@@ -828,17 +699,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
-name = "futures-macro"
-version = "0.3.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "futures-sink"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -859,7 +719,6 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-io",
- "futures-macro",
"futures-sink",
"futures-task",
"memchr",
@@ -943,16 +802,6 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.14.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
-dependencies = [
- "ahash",
- "allocator-api2",
-]
-
-[[package]]
-name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
@@ -979,15 +828,6 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "hashlink"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
-dependencies = [
- "hashbrown 0.14.5",
-]
-
-[[package]]
-name = "hashlink"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f"
@@ -1017,52 +857,6 @@ dependencies = [
]
[[package]]
-name = "hickory-proto"
-version = "0.25.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
-dependencies = [
- "async-trait",
- "cfg-if",
- "data-encoding",
- "enum-as-inner",
- "futures-channel",
- "futures-io",
- "futures-util",
- "idna 1.1.0",
- "ipnet",
- "once_cell",
- "rand 0.9.4",
- "ring",
- "thiserror 2.0.18",
- "tinyvec",
- "tokio",
- "tracing",
- "url",
-]
-
-[[package]]
-name = "hickory-resolver"
-version = "0.25.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a"
-dependencies = [
- "cfg-if",
- "futures-util",
- "hickory-proto",
- "ipconfig",
- "moka",
- "once_cell",
- "parking_lot",
- "rand 0.9.4",
- "resolv-conf",
- "smallvec",
- "thiserror 2.0.18",
- "tokio",
- "tracing",
-]
-
-[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1152,7 +946,7 @@ version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [
- "base64 0.22.1",
+ "base64",
"bytes",
"futures-channel",
"futures-util",
@@ -1347,19 +1141,6 @@ dependencies = [
]
[[package]]
-name = "ipconfig"
-version = "0.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222"
-dependencies = [
- "socket2",
- "widestring",
- "windows-registry",
- "windows-result",
- "windows-sys 0.61.2",
-]
-
-[[package]]
name = "ipnet"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1389,17 +1170,6 @@ dependencies = [
]
[[package]]
-name = "json5"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
-dependencies = [
- "pest",
- "pest_derive",
- "serde",
-]
-
-[[package]]
name = "k256"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1410,12 +1180,6 @@ dependencies = [
]
[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
-[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1484,15 +1248,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
-name = "matchers"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
-dependencies = [
- "regex-automata",
-]
-
-[[package]]
name = "mediatype"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1515,12 +1270,6 @@ dependencies = [
]
[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1542,46 +1291,19 @@ dependencies = [
]
[[package]]
-name = "moka"
-version = "0.12.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
-dependencies = [
- "crossbeam-channel",
- "crossbeam-epoch",
- "crossbeam-utils",
- "equivalent",
- "parking_lot",
- "portable-atomic",
- "smallvec",
- "tagptr",
- "uuid",
-]
-
-[[package]]
name = "negentropy"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0efe882e02d206d8d279c20eb40e03baf7cb5136a1476dc084a324fbc3ec42d"
[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
name = "nostr"
version = "0.44.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d8f0fe13526800300a36bf3b7c5f752e62e32ab81c74a8e5caa2865708625a"
dependencies = [
"aes",
- "base64 0.22.1",
+ "base64",
"bech32",
"bip39",
"bitcoin_hashes",
@@ -1663,12 +1385,6 @@ dependencies = [
]
[[package]]
-name = "num-conv"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
-
-[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1683,10 +1399,6 @@ name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
-dependencies = [
- "critical-section",
- "portable-atomic",
-]
[[package]]
name = "oorandom"
@@ -1701,16 +1413,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
-name = "ordered-multimap"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
-dependencies = [
- "dlv-list",
- "hashbrown 0.14.5",
-]
-
-[[package]]
name = "parking"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1751,12 +1453,6 @@ dependencies = [
]
[[package]]
-name = "pathdiff"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
-
-[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1773,49 +1469,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
-name = "pest"
-version = "2.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662"
-dependencies = [
- "memchr",
- "ucd-trie",
-]
-
-[[package]]
-name = "pest_derive"
-version = "2.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77"
-dependencies = [
- "pest",
- "pest_generator",
-]
-
-[[package]]
-name = "pest_generator"
-version = "2.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f"
-dependencies = [
- "pest",
- "pest_meta",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "pest_meta"
-version = "2.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220"
-dependencies = [
- "pest",
- "sha2",
-]
-
-[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1839,12 +1492,6 @@ dependencies = [
]
[[package]]
-name = "portable-atomic"
-version = "1.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3"
-
-[[package]]
name = "potential_utf"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1854,12 +1501,6 @@ dependencies = [
]
[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
-[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2068,37 +1709,13 @@ dependencies = [
]
[[package]]
-name = "radroots_event_store"
+name = "radroots_geonames"
version = "0.1.0-alpha"
dependencies = [
- "getrandom 0.2.17",
- "hex",
- "radroots_blossom",
- "radroots_event",
- "radroots_event_codec",
- "radroots_identity",
- "radroots_transport",
- "serde",
- "serde_json",
+ "fs2",
+ "rusqlite",
"sha2",
- "sqlx",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "radroots_geocoder"
-version = "0.1.0-alpha"
-dependencies = [
- "futures-executor",
- "hex",
- "radroots_runtime_paths",
- "reqwest",
- "serde",
- "sha2",
- "sqlx",
"tempfile",
- "thiserror 1.0.69",
- "tokio",
"url",
]
@@ -2120,18 +1737,6 @@ dependencies = [
]
[[package]]
-name = "radroots_log"
-version = "0.1.0-alpha"
-dependencies = [
- "chrono",
- "serde_json",
- "thiserror 1.0.69",
- "tracing",
- "tracing-appender",
- "tracing-subscriber",
-]
-
-[[package]]
name = "radroots_nostr"
version = "0.1.0-alpha"
dependencies = [
@@ -2161,52 +1766,6 @@ dependencies = [
]
[[package]]
-name = "radroots_nostr_signer"
-version = "0.1.0-alpha"
-dependencies = [
- "hex",
- "nostr",
- "radroots_identity",
- "radroots_nostr",
- "radroots_nostr_connect",
- "radroots_runtime",
- "serde",
- "serde_json",
- "sha2",
- "thiserror 1.0.69",
- "url",
- "uuid",
-]
-
-[[package]]
-name = "radroots_outbox"
-version = "0.1.0-alpha"
-dependencies = [
- "hex",
- "radroots_event",
- "radroots_event_store",
- "radroots_protocol",
- "radroots_transport",
- "serde",
- "serde_json",
- "sha2",
- "sqlx",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "radroots_protected_store"
-version = "0.1.0-alpha"
-dependencies = [
- "chacha20poly1305",
- "getrandom 0.2.17",
- "radroots_secret_vault",
- "serde",
- "serde_json",
- "zeroize",
-]
-
-[[package]]
name = "radroots_protocol"
version = "0.1.0-alpha"
dependencies = [
@@ -2270,114 +1829,64 @@ dependencies = [
name = "radroots_replica_sync"
version = "0.1.0-alpha"
dependencies = [
- "base64 0.22.1",
+ "base64",
"hex",
"radroots_core",
"radroots_event",
"radroots_event_codec",
"radroots_replica_schema",
- "radroots_replica_store",
- "radroots_sql_core",
- "serde",
- "serde_json",
- "sha2",
- "uuid",
-]
-
-[[package]]
-name = "radroots_replica_sync_wasm"
-version = "0.1.0-alpha"
-dependencies = [
- "base64 0.22.1",
- "radroots_event",
- "radroots_replica_sync",
- "radroots_sdk_sql_wasm_runtime",
- "serde",
- "serde-wasm-bindgen",
- "serde_json",
- "uuid",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "radroots_runtime"
-version = "0.1.0-alpha"
-dependencies = [
- "anyhow",
- "chacha20poly1305",
- "config",
- "getrandom 0.2.17",
- "radroots_log",
- "radroots_protected_store",
- "radroots_runtime_paths",
- "radroots_secret_vault",
- "serde",
- "serde_json",
- "tempfile",
- "thiserror 1.0.69",
- "tokio",
- "toml",
- "tracing",
- "zeroize",
+ "radroots_replica_store",
+ "radroots_sql_core",
+ "serde",
+ "serde_json",
+ "sha2",
+ "uuid",
]
[[package]]
-name = "radroots_runtime_contract_v1"
+name = "radroots_replica_sync_wasm"
version = "0.1.0-alpha"
dependencies = [
- "radroots_protocol_contract_v1",
+ "base64",
+ "radroots_event",
+ "radroots_replica_sync",
+ "radroots_sdk_sql_wasm_runtime",
"serde",
+ "serde-wasm-bindgen",
+ "serde_json",
+ "uuid",
+ "wasm-bindgen",
]
[[package]]
-name = "radroots_runtime_paths"
+name = "radroots_runtime_contract_v1"
version = "0.1.0-alpha"
dependencies = [
+ "radroots_protocol_contract_v1",
"serde",
- "thiserror 1.0.69",
]
[[package]]
name = "radroots_sdk"
version = "0.1.0-alpha"
dependencies = [
- "base64 0.22.1",
- "futures",
- "hex",
- "nostr",
"radroots_core",
"radroots_event",
"radroots_event_codec",
- "radroots_event_store",
- "radroots_geocoder",
+ "radroots_geonames",
"radroots_identity",
"radroots_nostr",
"radroots_nostr_connect",
- "radroots_nostr_signer",
- "radroots_outbox",
- "radroots_protected_store",
"radroots_protocol",
- "radroots_replica_schema",
- "radroots_replica_store",
- "radroots_replica_sync",
- "radroots_runtime_paths",
- "radroots_secret_vault",
"radroots_secrets",
"radroots_signing",
- "radroots_sql_core",
+ "radroots_storage",
+ "radroots_storage_sqlite",
+ "radroots_sync",
"radroots_trade",
"radroots_transport",
"radroots_transport_nostr",
- "radroots_transport_reticulum",
"reqwest",
- "serde",
- "serde_json",
- "sha2",
- "sqlx",
- "tempfile",
- "tokio",
- "tokio-tungstenite",
- "uuid",
]
[[package]]
@@ -2415,10 +1924,6 @@ dependencies = [
]
[[package]]
-name = "radroots_secret_vault"
-version = "0.1.0-alpha"
-
-[[package]]
name = "radroots_secrets"
version = "0.1.0-alpha"
dependencies = [
@@ -2440,18 +1945,52 @@ name = "radroots_sql_core"
version = "0.1.0-alpha"
dependencies = [
"chrono",
- "futures-executor",
"serde",
"serde_json",
- "sqlx",
"uuid",
]
[[package]]
+name = "radroots_storage"
+version = "0.1.0-alpha"
+dependencies = [
+ "radroots_event",
+ "radroots_protocol",
+ "radroots_trade",
+ "radroots_transport",
+]
+
+[[package]]
+name = "radroots_storage_sqlite"
+version = "0.1.0-alpha"
+dependencies = [
+ "fs2",
+ "radroots_event_codec",
+ "radroots_secrets",
+ "radroots_storage",
+ "sha2",
+ "sqlx",
+]
+
+[[package]]
+name = "radroots_sync"
+version = "0.1.0-alpha"
+dependencies = [
+ "radroots_event",
+ "radroots_event_codec",
+ "radroots_protocol",
+ "radroots_signing",
+ "radroots_storage",
+ "radroots_trade",
+ "radroots_transport",
+ "sha2",
+]
+
+[[package]]
name = "radroots_trade"
version = "0.1.0-alpha"
dependencies = [
- "base64 0.22.1",
+ "base64",
"hex",
"radroots_core",
"radroots_event",
@@ -2473,7 +2012,6 @@ dependencies = [
"radroots_event",
"radroots_identity",
"radroots_protocol",
- "serde",
"sha2",
]
@@ -2481,29 +2019,20 @@ dependencies = [
name = "radroots_transport_nostr"
version = "0.1.0-alpha"
dependencies = [
- "futures",
- "nostr",
+ "async-wsocket",
+ "nostr-relay-pool",
"nostr-sdk",
- "radroots_event",
- "radroots_event_store",
+ "radroots_event_codec",
"radroots_nostr",
- "radroots_outbox",
+ "radroots_protocol",
"radroots_transport",
- "serde",
"serde_json",
- "thiserror 1.0.69",
"tokio",
+ "tokio-tungstenite",
"url",
]
[[package]]
-name = "radroots_transport_reticulum"
-version = "0.1.0-alpha"
-dependencies = [
- "radroots_transport",
-]
-
-[[package]]
name = "rand"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2572,32 +2101,14 @@ dependencies = [
]
[[package]]
-name = "regex-automata"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
-
-[[package]]
name = "reqwest"
version = "0.12.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
dependencies = [
- "base64 0.22.1",
+ "base64",
"bytes",
"futures-core",
- "hickory-resolver",
"http",
"http-body",
"http-body-util",
@@ -2606,7 +2117,6 @@ dependencies = [
"hyper-util",
"js-sys",
"log",
- "once_cell",
"percent-encoding",
"pin-project-lite",
"quinn",
@@ -2629,12 +2139,6 @@ dependencies = [
]
[[package]]
-name = "resolv-conf"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
-
-[[package]]
name = "ring"
version = "0.17.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2649,25 +2153,27 @@ dependencies = [
]
[[package]]
-name = "ron"
-version = "0.8.1"
+name = "rsqlite-vfs"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
+checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c"
dependencies = [
- "base64 0.21.7",
- "bitflags",
- "serde",
- "serde_derive",
+ "hashbrown 0.16.1",
+ "thiserror 2.0.18",
]
[[package]]
-name = "rust-ini"
-version = "0.20.0"
+name = "rusqlite"
+version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a"
+checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e"
dependencies = [
- "cfg-if",
- "ordered-multimap",
+ "bitflags",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "libsqlite3-sys",
+ "smallvec",
+ "sqlite-wasm-rs",
]
[[package]]
@@ -2921,31 +2427,12 @@ dependencies = [
]
[[package]]
-name = "sharded-slab"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
-dependencies = [
- "lazy_static",
-]
-
-[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
-name = "signal-hook-registry"
-version = "1.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
-dependencies = [
- "errno",
- "libc",
-]
-
-[[package]]
name = "simd-adler32"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2983,6 +2470,18 @@ dependencies = [
]
[[package]]
+name = "sqlite-wasm-rs"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75"
+dependencies = [
+ "cc",
+ "js-sys",
+ "rsqlite-vfs",
+ "wasm-bindgen",
+]
+
+[[package]]
name = "sqlx"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2999,7 +2498,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb"
dependencies = [
- "base64 0.22.1",
+ "base64",
"bytes",
"cfg-if",
"crc",
@@ -3011,7 +2510,7 @@ dependencies = [
"futures-io",
"futures-util",
"hashbrown 0.16.1",
- "hashlink 0.11.1",
+ "hashlink",
"indexmap",
"log",
"memchr",
@@ -3099,12 +2598,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
-name = "symlink"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a"
-
-[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3136,12 +2629,6 @@ dependencies = [
]
[[package]]
-name = "tagptr"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
-
-[[package]]
name = "tar"
version = "0.4.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3206,54 +2693,6 @@ dependencies = [
]
[[package]]
-name = "thread_local"
-version = "1.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "time"
-version = "0.3.49"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
-dependencies = [
- "deranged",
- "num-conv",
- "powerfmt",
- "serde_core",
- "time-core",
- "time-macros",
-]
-
-[[package]]
-name = "time-core"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
-
-[[package]]
-name = "time-macros"
-version = "0.2.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d"
-dependencies = [
- "num-conv",
- "time-core",
-]
-
-[[package]]
-name = "tiny-keccak"
-version = "2.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
-dependencies = [
- "crunchy",
-]
-
-[[package]]
name = "tinystr"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3288,7 +2727,6 @@ dependencies = [
"libc",
"mio",
"pin-project-lite",
- "signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
@@ -3453,19 +2891,6 @@ dependencies = [
]
[[package]]
-name = "tracing-appender"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c"
-dependencies = [
- "crossbeam-channel",
- "symlink",
- "thiserror 2.0.18",
- "time",
- "tracing-subscriber",
-]
-
-[[package]]
name = "tracing-attributes"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3483,36 +2908,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
- "valuable",
-]
-
-[[package]]
-name = "tracing-log"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
-dependencies = [
- "log",
- "once_cell",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-subscriber"
-version = "0.3.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
-dependencies = [
- "matchers",
- "nu-ansi-term",
- "once_cell",
- "regex-automata",
- "sharded-slab",
- "smallvec",
- "thread_local",
- "tracing",
- "tracing-core",
- "tracing-log",
]
[[package]]
@@ -3547,12 +2942,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
-name = "ucd-trie"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
-
-[[package]]
name = "unicode-bidi"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3580,12 +2969,6 @@ dependencies = [
]
[[package]]
-name = "unicode-segmentation"
-version = "1.13.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
-
-[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3656,12 +3039,6 @@ dependencies = [
]
[[package]]
-name = "valuable"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
-
-[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3884,10 +3261,20 @@ dependencies = [
]
[[package]]
-name = "widestring"
-version = "1.2.1"
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
@@ -3899,6 +3286,12 @@ dependencies = [
]
[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3940,17 +3333,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
-name = "windows-registry"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
-dependencies = [
- "windows-link",
- "windows-result",
- "windows-strings",
-]
-
-[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4244,17 +3626,6 @@ dependencies = [
]
[[package]]
-name = "yaml-rust2"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8"
-dependencies = [
- "arraydeque",
- "encoding_rs",
- "hashlink 0.8.4",
-]
-
-[[package]]
name = "yoke"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4362,3 +3733,35 @@ name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+
+[[patch.unused]]
+name = "radroots_event_store"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_geocoder"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_nostr_signer"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_outbox"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_protected_store"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_runtime_paths"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_secret_vault"
+version = "0.1.0-alpha"
+
+[[patch.unused]]
+name = "radroots_transport_reticulum"
+version = "0.1.0-alpha"
diff --git a/Cargo.toml b/Cargo.toml
@@ -55,6 +55,7 @@ radroots_event = { package = "radroots_event", version = "=0.1.0-alpha", default
radroots_event_codec = { package = "radroots_event_codec", version = "=0.1.0-alpha", default-features = false }
radroots_event_index = { version = "=0.1.0-alpha", default-features = false }
radroots_geocoder = { version = "=0.1.0-alpha" }
+radroots_geonames = { package = "radroots_geonames", version = "=0.1.0-alpha", default-features = false }
radroots_identity = { package = "radroots_identity", version = "=0.1.0-alpha", default-features = false, features = [
"std",
] }
@@ -69,6 +70,9 @@ radroots_runtime_contract_v1 = { path = "crates/runtime_contract_v1", version =
radroots_secret_vault = { version = "=0.1.0-alpha", default-features = false }
radroots_secrets = { package = "radroots_secrets", version = "=0.1.0-alpha", default-features = false }
radroots_signing = { package = "radroots_signing", version = "=0.1.0-alpha", default-features = false }
+radroots_storage = { package = "radroots_storage", version = "=0.1.0-alpha", default-features = false }
+radroots_storage_sqlite = { package = "radroots_storage_sqlite", version = "=0.1.0-alpha", default-features = false }
+radroots_sync = { package = "radroots_sync", version = "=0.1.0-alpha", default-features = false }
radroots_transport = { package = "radroots_transport", version = "=0.1.0-alpha", default-features = false }
radroots_transport_nostr = { package = "radroots_transport_nostr", version = "=0.1.0-alpha", default-features = false }
radroots_transport_reticulum = { version = "=0.1.0-alpha", default-features = false }
diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml
@@ -6,236 +6,80 @@ edition.workspace = true
authors.workspace = true
rust-version.workspace = true
license.workspace = true
-description = "Public Rust SDK for Radroots"
+description = "Host-neutral asynchronous client engine for Radroots"
repository.workspace = true
homepage.workspace = true
readme = "README.md"
+autotests = false
+autoexamples = false
[lib]
name = "radroots_sdk"
[features]
-default = ["std", "serde", "serde_json", "identity-models"]
-std = [
- "radroots_event/std",
- "radroots_event_codec/std",
- "radroots_trade/std",
-]
-serde = [
- "dep:serde",
- "radroots_event/serde",
- "radroots_trade/serde",
-]
-serde_json = [
- "dep:serde_json",
- "serde",
- "nostr",
- "radroots_event_codec/json",
- "radroots_trade/serde_json",
-]
-nostr = []
-knowledge = [
- "serde",
- "serde_json",
- "radroots_event/knowledge",
- "radroots_event_codec/manifests",
-]
-identity-models = [
- "radroots_identity/std",
-]
-signing = [
- "dep:nostr",
+default = ["memory"]
+memory = ["radroots_storage/memory"]
+sqlite = ["dep:radroots_storage_sqlite"]
+sync = ["dep:radroots_sync"]
+nostr = [
+ "sync",
"dep:radroots_nostr",
- "dep:radroots_protocol",
- "nostr",
- "radroots_nostr/std",
- "radroots_protocol/std",
- "radroots_signing/std",
-]
-transport-nostr-client = [
- "signing",
- "std",
- "serde_json",
- "dep:radroots_transport_nostr",
- "radroots_transport_nostr/client",
-]
-radrootsd-execution = [
- "std",
- "serde_json",
- "dep:futures",
- "dep:radroots_protocol",
- "dep:radroots_transport",
"dep:radroots_transport_nostr",
- "dep:reqwest",
- "radroots_protocol/serde",
- "radroots_protocol/std",
- "radroots_transport/serde",
- "radroots_transport_nostr/std",
]
-signer-adapters = [
- "identity-models",
- "local-signer",
- "signing",
- "std",
+nip46 = [
+ "nostr",
"dep:radroots_nostr_connect",
- "dep:radroots_nostr_signer",
- "dep:tokio",
- "radroots_nostr/events",
]
-runtime = [
- "std",
- "serde_json",
- "dep:tokio",
- "dep:base64",
- "dep:hex",
- "dep:radroots_event_store",
- "dep:radroots_geocoder",
- "dep:radroots_outbox",
- "dep:radroots_protected_store",
- "dep:radroots_protocol",
- "dep:radroots_transport",
- "dep:radroots_transport_nostr",
- "dep:radroots_transport_reticulum",
- "dep:radroots_runtime_paths",
- "dep:radroots_secret_vault",
- "dep:sha2",
- "dep:sqlx",
- "dep:uuid",
- "radroots_signing/std",
- "radroots_event_store/sqlite",
- "radroots_event_store/runtime-tokio",
- "radroots_outbox/sqlite",
- "radroots_outbox/runtime-tokio",
- "radroots_protected_store/std",
- "radroots_protocol/std",
- "radroots_secret_vault/std",
- "radroots_transport/serde",
- "radroots_transport_nostr/std",
- "radroots_transport_nostr/storage",
- "radroots_transport_nostr/runtime-tokio",
-]
-local-signer = [
- "runtime",
- "signing",
+local-signing = [
"dep:radroots_secrets",
"radroots_nostr/signing",
]
-transport-nostr-runtime = [
- "runtime",
- "dep:radroots_nostr",
- "radroots_transport_nostr/client",
-]
-local-runtime = [
- "std",
- "serde",
- "serde_json",
- "runtime",
- "signer-adapters",
- "transport-nostr-runtime",
- "transport-nostr-client",
+radrootsd = [
+ "sync",
+ "dep:reqwest",
]
-local-runtime-radrootsd-execution = [
- "std",
- "serde",
- "serde_json",
- "runtime",
- "signer-adapters",
- "radrootsd-execution",
+geonames = ["dep:radroots_geonames"]
+knowledge = [
+ "radroots_event/knowledge",
+ "radroots_event_codec/knowledge",
]
-test-fixture-geonames-asset = [
- "runtime",
- "radroots_geocoder/test-fixture-geonames-asset",
+native = ["sqlite", "sync", "local-signing"]
+full = [
+ "native",
+ "nostr",
+ "nip46",
+ "radrootsd",
+ "geonames",
+ "knowledge",
]
[dependencies]
-base64 = { workspace = true, optional = true }
-futures = { workspace = true, optional = true }
-radroots_event_store = { workspace = true, optional = true, default-features = false }
+radroots_core = { workspace = true, default-features = false }
radroots_event = { workspace = true, default-features = false }
radroots_event_codec = { workspace = true, default-features = false }
-radroots_geocoder = { workspace = true, optional = true }
-radroots_outbox = { workspace = true, optional = true, default-features = false }
-radroots_protocol = { workspace = true, optional = true, default-features = false }
-radroots_protected_store = { workspace = true, optional = true, default-features = false }
-radroots_transport = { workspace = true, optional = true, default-features = false }
-radroots_transport_nostr = { workspace = true, optional = true, default-features = false }
-radroots_transport_reticulum = { workspace = true, optional = true, default-features = false }
-radroots_runtime_paths = { workspace = true, optional = true, default-features = false }
-radroots_secret_vault = { workspace = true, optional = true, default-features = false }
-radroots_secrets = { workspace = true, optional = true, default-features = false }
+radroots_identity = { workspace = true, default-features = false }
+radroots_protocol = { workspace = true, default-features = false }
radroots_signing = { workspace = true, default-features = false }
+radroots_storage = { workspace = true, default-features = false }
radroots_trade = { workspace = true, default-features = false }
-radroots_identity = { workspace = true, default-features = false }
+radroots_transport = { workspace = true, default-features = false }
+
+radroots_geonames = { workspace = true, optional = true, default-features = false }
radroots_nostr = { workspace = true, optional = true, default-features = false }
-radroots_nostr_connect = { workspace = true, optional = true }
-radroots_nostr_signer = { workspace = true, optional = true, default-features = false }
+radroots_nostr_connect = { workspace = true, optional = true, default-features = false }
+radroots_secrets = { workspace = true, optional = true, default-features = false }
+radroots_storage_sqlite = { workspace = true, optional = true, default-features = false }
+radroots_sync = { workspace = true, optional = true, default-features = false }
+radroots_transport_nostr = { workspace = true, optional = true, default-features = false }
+
reqwest = { workspace = true, optional = true, default-features = false, features = [
"json",
"rustls-tls",
] }
-hex = { workspace = true, optional = true }
-nostr = { workspace = true, optional = true }
-serde = { workspace = true, optional = true, default-features = false, features = [
- "derive",
- "alloc",
-] }
-serde_json = { workspace = true, optional = true, default-features = false, features = [
- "alloc",
-] }
-sha2 = { workspace = true, optional = true }
-sqlx = { version = "0.9.0", optional = true, default-features = false, features = [
- "runtime-tokio",
- "sqlite-bundled",
-] }
-tokio = { workspace = true, optional = true, features = ["macros", "rt", "sync", "time"] }
-uuid = { workspace = true, optional = true }
-
-[[example]]
-name = "sdk_v1_listing_prepare"
-path = "examples/sdk_v1_listing_prepare.rs"
-required-features = ["runtime"]
-
-[[example]]
-name = "sdk_v1_knowledge_prepare"
-path = "examples/sdk_v1_knowledge_prepare.rs"
-required-features = ["knowledge"]
-
-[[example]]
-name = "sdk_v1_local_enqueue_and_mock_sync"
-path = "examples/sdk_v1_local_enqueue_and_mock_sync.rs"
-required-features = ["runtime", "signer-adapters"]
-
-[[example]]
-name = "sdk_v1_myc_nip46_signer_setup"
-path = "examples/sdk_v1_myc_nip46_signer_setup.rs"
-required-features = ["runtime", "signer-adapters"]
-[[example]]
-name = "runtime_local"
-path = "examples/runtime_local.rs"
-required-features = ["local-runtime"]
-
-[dev-dependencies]
-futures = { workspace = true }
-nostr = { workspace = true }
-radroots_core = { workspace = true, default-features = false, features = [
- "std",
-] }
-radroots_signing = { workspace = true, default-features = false, features = ["std"] }
-radroots_replica_store = { workspace = true, default-features = false, features = [
- "native",
-] }
-radroots_replica_schema = { workspace = true }
-radroots_replica_sync = { workspace = true, features = ["std", "legacy-ingest"] }
-radroots_sql_core = { workspace = true, features = ["native"] }
-radroots_nostr = { workspace = true, default-features = false, features = [
- "std",
- "events",
- "signing",
-] }
-tempfile = { workspace = true }
-tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
-tokio-tungstenite = "0.26.2"
+[[test]]
+name = "package_boundary"
+path = "tests/package_boundary.rs"
[lints]
workspace = true
diff --git a/crates/sdk/src/capability.rs b/crates/sdk/src/capability.rs
@@ -0,0 +1 @@
+//! Client capability reporting.
diff --git a/crates/sdk/src/client.rs b/crates/sdk/src/client.rs
@@ -0,0 +1 @@
+//! Client construction and lifecycle.
diff --git a/crates/sdk/src/diagnostics.rs b/crates/sdk/src/diagnostics.rs
@@ -0,0 +1 @@
+//! Redacted client diagnostics.
diff --git a/crates/sdk/src/error.rs b/crates/sdk/src/error.rs
@@ -1,1349 +1 @@
-#[cfg(feature = "runtime")]
-use std::{fmt, path::PathBuf};
-
-#[cfg(feature = "runtime")]
-use crate::privacy::{PrivacyPreflightStatus, ProductSensitivityField};
-#[cfg(feature = "runtime")]
-use crate::transport::ReticulumBehavior;
-#[cfg(feature = "runtime")]
-use radroots_event::trade::validation::OperationalListingValidationError;
-#[cfg(feature = "runtime")]
-use serde_json::{Value, json};
-
-#[cfg(feature = "runtime")]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum RadrootsSdkErrorClass {
- Authorization,
- Clock,
- Configuration,
- Request,
- Storage,
- Transport,
- Unsupported,
-}
-
-#[cfg(feature = "runtime")]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum RadrootsSdkRecoveryAction {
- InspectLocalStores,
- InspectGeoNamesAsset,
- RetryOperationWithSameIdempotencyKey,
- ConfigureTransportTargets,
- ConfigureGeoNamesCache,
- ConfigureSigner,
- FixRequest,
- SelectAuthorizedActor,
- CompleteSignerAuthentication,
- RetryAfterTransportFailure,
- RetryGeoNamesDownload,
- EnableRequiredFeature,
-}
-
-#[cfg(feature = "runtime")]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum RadrootsSdkGeoNamesErrorKind {
- Configuration,
- Download,
- Cache,
- Integrity,
- Schema,
- Lookup,
-}
-
-#[cfg(feature = "runtime")]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum RadrootsSdkListingValidationErrorKind {
- InvalidKind,
- InvalidProfile,
- MissingListingId,
- ListingEventNotFound,
- ListingEventFetchFailed,
- ParseError,
- InvalidSeller,
- MissingFarmProfile,
- MissingFarmRecord,
- MissingTitle,
- MissingDescription,
- MissingProductType,
- MissingBins,
- MissingPrimaryBin,
- InvalidBin,
- MissingPrice,
- InvalidPrice,
- MissingInventory,
- InvalidInventory,
- MissingAvailability,
- MissingLocation,
- MissingLocationLocality,
- MissingLocationGeohash,
- InvalidLocationGeohash,
- MissingDeliveryMethod,
-}
-
-#[cfg(feature = "runtime")]
-impl From<&OperationalListingValidationError> for RadrootsSdkListingValidationErrorKind {
- fn from(error: &OperationalListingValidationError) -> Self {
- match error {
- OperationalListingValidationError::InvalidKind { .. } => Self::InvalidKind,
- OperationalListingValidationError::InvalidProfile => Self::InvalidProfile,
- OperationalListingValidationError::MissingListingId => Self::MissingListingId,
- OperationalListingValidationError::ListingEventNotFound { .. } => {
- Self::ListingEventNotFound
- }
- OperationalListingValidationError::ListingEventFetchFailed { .. } => {
- Self::ListingEventFetchFailed
- }
- OperationalListingValidationError::ParseError { .. } => Self::ParseError,
- OperationalListingValidationError::InvalidSeller => Self::InvalidSeller,
- OperationalListingValidationError::MissingFarmProfile => Self::MissingFarmProfile,
- OperationalListingValidationError::MissingFarmRecord => Self::MissingFarmRecord,
- OperationalListingValidationError::MissingTitle => Self::MissingTitle,
- OperationalListingValidationError::MissingDescription => Self::MissingDescription,
- OperationalListingValidationError::MissingProductType => Self::MissingProductType,
- OperationalListingValidationError::MissingBins => Self::MissingBins,
- OperationalListingValidationError::MissingPrimaryBin => Self::MissingPrimaryBin,
- OperationalListingValidationError::InvalidBin => Self::InvalidBin,
- OperationalListingValidationError::MissingPrice => Self::MissingPrice,
- OperationalListingValidationError::InvalidPrice => Self::InvalidPrice,
- OperationalListingValidationError::MissingInventory => Self::MissingInventory,
- OperationalListingValidationError::InvalidInventory => Self::InvalidInventory,
- OperationalListingValidationError::MissingAvailability => Self::MissingAvailability,
- OperationalListingValidationError::MissingLocation => Self::MissingLocation,
- OperationalListingValidationError::MissingLocationLocality => {
- Self::MissingLocationLocality
- }
- OperationalListingValidationError::MissingLocationGeohash => {
- Self::MissingLocationGeohash
- }
- OperationalListingValidationError::InvalidLocationGeohash => {
- Self::InvalidLocationGeohash
- }
- OperationalListingValidationError::MissingDeliveryMethod => Self::MissingDeliveryMethod,
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum RadrootsSdkTradeErrorKind {
- InvalidEnvelope,
- InvalidCommandBody,
- PrivateArtifactMissing,
- PrivateArtifactCommitmentMismatch,
- PrivateArtifactAcknowledgementMissing,
- TradeNotFound,
- QueryLimitInvalid,
- CursorInvalid,
-}
-
-#[cfg(feature = "runtime")]
-impl RadrootsSdkTradeErrorKind {
- pub fn code(self) -> &'static str {
- match self {
- Self::InvalidEnvelope => "trade_invalid_envelope",
- Self::InvalidCommandBody => "trade_invalid_command_body",
- Self::PrivateArtifactMissing => "trade_private_artifact_missing",
- Self::PrivateArtifactCommitmentMismatch => "trade_private_artifact_commitment_mismatch",
- Self::PrivateArtifactAcknowledgementMissing => {
- "trade_private_artifact_acknowledgement_missing"
- }
- Self::TradeNotFound => "trade_not_found",
- Self::QueryLimitInvalid => "trade_query_limit_invalid",
- Self::CursorInvalid => "trade_cursor_invalid",
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-const RECOVERY_INSPECT_LOCAL_STORES: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::InspectLocalStores];
-#[cfg(feature = "runtime")]
-const RECOVERY_INSPECT_GEONAMES_ASSET: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::InspectGeoNamesAsset];
-#[cfg(feature = "runtime")]
-const RECOVERY_RETRY_OPERATION_WITH_SAME_IDEMPOTENCY_KEY: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::RetryOperationWithSameIdempotencyKey];
-#[cfg(feature = "runtime")]
-const RECOVERY_CONFIGURE_TRANSPORT_TARGETS: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::ConfigureTransportTargets];
-#[cfg(feature = "runtime")]
-const RECOVERY_CONFIGURE_GEONAMES_CACHE: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::ConfigureGeoNamesCache];
-#[cfg(feature = "runtime")]
-const RECOVERY_CONFIGURE_SIGNER: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::ConfigureSigner];
-#[cfg(feature = "runtime")]
-const RECOVERY_FIX_REQUEST: &[RadrootsSdkRecoveryAction] = &[RadrootsSdkRecoveryAction::FixRequest];
-#[cfg(feature = "runtime")]
-const RECOVERY_SELECT_AUTHORIZED_ACTOR: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::SelectAuthorizedActor];
-#[cfg(feature = "runtime")]
-const RECOVERY_COMPLETE_SIGNER_AUTHENTICATION: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::CompleteSignerAuthentication];
-#[cfg(feature = "runtime")]
-const RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::RetryAfterTransportFailure];
-#[cfg(feature = "runtime")]
-const RECOVERY_RETRY_GEONAMES_DOWNLOAD: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::RetryGeoNamesDownload];
-#[cfg(feature = "runtime")]
-const RECOVERY_ENABLE_REQUIRED_FEATURE: &[RadrootsSdkRecoveryAction] =
- &[RadrootsSdkRecoveryAction::EnableRequiredFeature];
-
-#[cfg(feature = "runtime")]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-pub struct RadrootsSdkErrorCatalogEntry {
- pub code: &'static str,
- pub class: RadrootsSdkErrorClass,
- pub retryable: bool,
- pub recovery_actions: &'static [RadrootsSdkRecoveryAction],
-}
-
-#[cfg(feature = "runtime")]
-impl RadrootsSdkErrorCatalogEntry {
- const fn new(
- code: &'static str,
- class: RadrootsSdkErrorClass,
- retryable: bool,
- recovery_actions: &'static [RadrootsSdkRecoveryAction],
- ) -> Self {
- Self {
- code,
- class,
- retryable,
- recovery_actions,
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-pub const RADROOTS_SDK_ERROR_CATALOG: &[RadrootsSdkErrorCatalogEntry] = &[
- RadrootsSdkErrorCatalogEntry::new(
- "io",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "clock_before_unix_epoch",
- RadrootsSdkErrorClass::Clock,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "timestamp_out_of_range",
- RadrootsSdkErrorClass::Clock,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "unauthorized_actor",
- RadrootsSdkErrorClass::Authorization,
- false,
- RECOVERY_SELECT_AUTHORIZED_ACTOR,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_pubkey_mismatch",
- RadrootsSdkErrorClass::Authorization,
- false,
- RECOVERY_SELECT_AUTHORIZED_ACTOR,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_unavailable",
- RadrootsSdkErrorClass::Configuration,
- false,
- RECOVERY_CONFIGURE_SIGNER,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_request_rejected",
- RadrootsSdkErrorClass::Authorization,
- false,
- RECOVERY_SELECT_AUTHORIZED_ACTOR,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_request_timed_out",
- RadrootsSdkErrorClass::Transport,
- true,
- RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_auth_challenge_pending",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_COMPLETE_SIGNER_AUTHENTICATION,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_transport",
- RadrootsSdkErrorClass::Transport,
- true,
- RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_protocol",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "signer_returned_event_drift",
- RadrootsSdkErrorClass::Authorization,
- false,
- RECOVERY_CONFIGURE_SIGNER,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "empty_transport_targets",
- RadrootsSdkErrorClass::Configuration,
- false,
- RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "transport_target_limit_exceeded",
- RadrootsSdkErrorClass::Configuration,
- false,
- RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "invalid_relay_url",
- RadrootsSdkErrorClass::Configuration,
- false,
- RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "idempotency_conflict",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_RETRY_OPERATION_WITH_SAME_IDEMPOTENCY_KEY,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_invalid_envelope",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_invalid_command_body",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_private_artifact_missing",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_private_artifact_commitment_mismatch",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_private_artifact_acknowledgement_missing",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_not_found",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_query_limit_invalid",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "trade_cursor_invalid",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "privacy_preflight",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "product_sync_unsupported",
- RadrootsSdkErrorClass::Unsupported,
- false,
- RECOVERY_ENABLE_REQUIRED_FEATURE,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "reticulum_transport_unavailable",
- RadrootsSdkErrorClass::Unsupported,
- false,
- RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "reticulum_transport_deferred",
- RadrootsSdkErrorClass::Unsupported,
- false,
- RECOVERY_CONFIGURE_TRANSPORT_TARGETS,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "product_sync_transport_setup_failure",
- RadrootsSdkErrorClass::Transport,
- true,
- RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "authority",
- RadrootsSdkErrorClass::Authorization,
- false,
- RECOVERY_SELECT_AUTHORIZED_ACTOR,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "event_store",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "invalid_request",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "unsupported_profile_schema",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "listing_edit",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "listing_validation",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "listing_mutation",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "outbox",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "private_store",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "studio_store",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "geonames_configuration",
- RadrootsSdkErrorClass::Configuration,
- false,
- RECOVERY_CONFIGURE_GEONAMES_CACHE,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "geonames_download",
- RadrootsSdkErrorClass::Transport,
- true,
- RECOVERY_RETRY_GEONAMES_DOWNLOAD,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "geonames_cache",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_GEONAMES_ASSET,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "geonames_integrity",
- RadrootsSdkErrorClass::Storage,
- false,
- RECOVERY_INSPECT_GEONAMES_ASSET,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "geonames_schema",
- RadrootsSdkErrorClass::Storage,
- false,
- RECOVERY_INSPECT_GEONAMES_ASSET,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "geonames_lookup",
- RadrootsSdkErrorClass::Request,
- false,
- RECOVERY_FIX_REQUEST,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "transport",
- RadrootsSdkErrorClass::Transport,
- true,
- RECOVERY_RETRY_AFTER_TRANSPORT_FAILURE,
- ),
- RadrootsSdkErrorCatalogEntry::new(
- "projection",
- RadrootsSdkErrorClass::Storage,
- true,
- RECOVERY_INSPECT_LOCAL_STORES,
- ),
-];
-
-#[cfg(feature = "runtime")]
-pub fn radroots_sdk_error_catalog() -> &'static [RadrootsSdkErrorCatalogEntry] {
- RADROOTS_SDK_ERROR_CATALOG
-}
-
-#[cfg(feature = "runtime")]
-#[derive(Debug)]
-#[non_exhaustive]
-pub enum RadrootsSdkError {
- Io {
- path: PathBuf,
- message: String,
- },
- ClockBeforeUnixEpoch,
- TimestampOutOfRange {
- value: u64,
- },
- UnauthorizedActor {
- operation: String,
- reason: String,
- },
- SignerPubkeyMismatch {
- operation: String,
- expected_pubkey_prefix: String,
- signer_pubkey_prefix: String,
- },
- SignerUnavailable {
- mode: String,
- reason: String,
- },
- SignerRequestRejected {
- mode: String,
- reason: String,
- },
- SignerRequestTimedOut {
- mode: String,
- },
- SignerAuthChallengePending {
- mode: String,
- auth_url: Option<String>,
- },
- SignerTransport {
- mode: String,
- reason: String,
- },
- SignerProtocol {
- mode: String,
- reason: String,
- },
- SignerReturnedEventDrift {
- operation: String,
- reason: String,
- },
- EmptyTransportTargets {
- operation: String,
- },
- TransportTargetLimitExceeded {
- max: usize,
- actual: usize,
- },
- InvalidRelayUrl {
- url: String,
- reason: String,
- },
- IdempotencyConflict {
- operation_kind: String,
- expected_pubkey_prefix: String,
- existing_digest_prefix: String,
- new_digest_prefix: String,
- },
- Trade {
- kind: RadrootsSdkTradeErrorKind,
- operation: String,
- message: String,
- },
- PrivacyPreflight {
- operation: String,
- status: PrivacyPreflightStatus,
- fields: Vec<ProductSensitivityField>,
- },
- ProductSyncUnsupported {
- operation: &'static str,
- required_feature: &'static str,
- },
- ReticulumTransportUnavailable {
- operation: String,
- endpoint_uri: String,
- behavior: ReticulumBehavior,
- },
- ProductSyncTransportSetupFailure {
- message: String,
- },
- Authority {
- message: String,
- },
- EventStore {
- message: String,
- },
- InvalidRequest {
- message: String,
- },
- UnsupportedProfileSchema {
- path: PathBuf,
- message: String,
- },
- ListingEdit {
- message: String,
- },
- ListingValidation {
- kind: RadrootsSdkListingValidationErrorKind,
- message: String,
- },
- ListingMutation {
- message: String,
- },
- Outbox {
- message: String,
- },
- PrivateStore {
- message: String,
- },
- StudioStore {
- message: String,
- },
- GeoNames {
- kind: RadrootsSdkGeoNamesErrorKind,
- message: String,
- },
- Transport {
- message: String,
- },
- Projection {
- message: String,
- },
-}
-
-#[cfg(feature = "runtime")]
-impl RadrootsSdkError {
- pub fn code(&self) -> &'static str {
- match self {
- Self::Io { .. } => "io",
- Self::ClockBeforeUnixEpoch => "clock_before_unix_epoch",
- Self::TimestampOutOfRange { .. } => "timestamp_out_of_range",
- Self::UnauthorizedActor { .. } => "unauthorized_actor",
- Self::SignerPubkeyMismatch { .. } => "signer_pubkey_mismatch",
- Self::SignerUnavailable { .. } => "signer_unavailable",
- Self::SignerRequestRejected { .. } => "signer_request_rejected",
- Self::SignerRequestTimedOut { .. } => "signer_request_timed_out",
- Self::SignerAuthChallengePending { .. } => "signer_auth_challenge_pending",
- Self::SignerTransport { .. } => "signer_transport",
- Self::SignerProtocol { .. } => "signer_protocol",
- Self::SignerReturnedEventDrift { .. } => "signer_returned_event_drift",
- Self::EmptyTransportTargets { .. } => "empty_transport_targets",
- Self::TransportTargetLimitExceeded { .. } => "transport_target_limit_exceeded",
- Self::InvalidRelayUrl { .. } => "invalid_relay_url",
- Self::IdempotencyConflict { .. } => "idempotency_conflict",
- Self::Trade { kind, .. } => kind.code(),
- Self::PrivacyPreflight { .. } => "privacy_preflight",
- Self::ProductSyncUnsupported { .. } => "product_sync_unsupported",
- Self::ReticulumTransportUnavailable { behavior, .. } => match behavior {
- ReticulumBehavior::RejectDeliveryAttempts => "reticulum_transport_unavailable",
- ReticulumBehavior::DeferDeliveryPlans => "reticulum_transport_deferred",
- },
- Self::ProductSyncTransportSetupFailure { .. } => "product_sync_transport_setup_failure",
- Self::Authority { .. } => "authority",
- Self::EventStore { .. } => "event_store",
- Self::InvalidRequest { .. } => "invalid_request",
- Self::UnsupportedProfileSchema { .. } => "unsupported_profile_schema",
- Self::ListingEdit { .. } => "listing_edit",
- Self::ListingValidation { .. } => "listing_validation",
- Self::ListingMutation { .. } => "listing_mutation",
- Self::Outbox { .. } => "outbox",
- Self::PrivateStore { .. } => "private_store",
- Self::StudioStore { .. } => "studio_store",
- Self::GeoNames { kind, .. } => match kind {
- RadrootsSdkGeoNamesErrorKind::Configuration => "geonames_configuration",
- RadrootsSdkGeoNamesErrorKind::Download => "geonames_download",
- RadrootsSdkGeoNamesErrorKind::Cache => "geonames_cache",
- RadrootsSdkGeoNamesErrorKind::Integrity => "geonames_integrity",
- RadrootsSdkGeoNamesErrorKind::Schema => "geonames_schema",
- RadrootsSdkGeoNamesErrorKind::Lookup => "geonames_lookup",
- },
- Self::Transport { .. } => "transport",
- Self::Projection { .. } => "projection",
- }
- }
-
- pub fn class(&self) -> RadrootsSdkErrorClass {
- match self {
- Self::Io { .. }
- | Self::EventStore { .. }
- | Self::Outbox { .. }
- | Self::PrivateStore { .. }
- | Self::StudioStore { .. }
- | Self::Projection { .. } => RadrootsSdkErrorClass::Storage,
- Self::GeoNames { kind, .. } => match kind {
- RadrootsSdkGeoNamesErrorKind::Configuration => RadrootsSdkErrorClass::Configuration,
- RadrootsSdkGeoNamesErrorKind::Download => RadrootsSdkErrorClass::Transport,
- RadrootsSdkGeoNamesErrorKind::Cache
- | RadrootsSdkGeoNamesErrorKind::Integrity
- | RadrootsSdkGeoNamesErrorKind::Schema => RadrootsSdkErrorClass::Storage,
- RadrootsSdkGeoNamesErrorKind::Lookup => RadrootsSdkErrorClass::Request,
- },
- Self::ClockBeforeUnixEpoch | Self::TimestampOutOfRange { .. } => {
- RadrootsSdkErrorClass::Clock
- }
- Self::UnauthorizedActor { .. }
- | Self::SignerPubkeyMismatch { .. }
- | Self::SignerRequestRejected { .. }
- | Self::SignerReturnedEventDrift { .. }
- | Self::Authority { .. } => RadrootsSdkErrorClass::Authorization,
- Self::SignerUnavailable { .. } => RadrootsSdkErrorClass::Configuration,
- Self::EmptyTransportTargets { .. }
- | Self::TransportTargetLimitExceeded { .. }
- | Self::InvalidRelayUrl { .. } => RadrootsSdkErrorClass::Configuration,
- Self::IdempotencyConflict { .. }
- | Self::Trade { .. }
- | Self::PrivacyPreflight { .. }
- | Self::SignerProtocol { .. }
- | Self::SignerAuthChallengePending { .. }
- | Self::InvalidRequest { .. }
- | Self::UnsupportedProfileSchema { .. }
- | Self::ListingEdit { .. }
- | Self::ListingValidation { .. }
- | Self::ListingMutation { .. } => RadrootsSdkErrorClass::Request,
- Self::ProductSyncUnsupported { .. } | Self::ReticulumTransportUnavailable { .. } => {
- RadrootsSdkErrorClass::Unsupported
- }
- Self::ProductSyncTransportSetupFailure { .. }
- | Self::Transport { .. }
- | Self::SignerRequestTimedOut { .. }
- | Self::SignerTransport { .. } => RadrootsSdkErrorClass::Transport,
- }
- }
-
- pub fn retryable(&self) -> bool {
- matches!(
- self,
- Self::Io { .. }
- | Self::ProductSyncTransportSetupFailure { .. }
- | Self::EventStore { .. }
- | Self::Outbox { .. }
- | Self::PrivateStore { .. }
- | Self::StudioStore { .. }
- | Self::GeoNames {
- kind: RadrootsSdkGeoNamesErrorKind::Cache
- | RadrootsSdkGeoNamesErrorKind::Download,
- ..
- }
- | Self::Transport { .. }
- | Self::SignerRequestTimedOut { .. }
- | Self::SignerTransport { .. }
- | Self::Projection { .. }
- )
- }
-
- pub fn recovery_actions(&self) -> Vec<RadrootsSdkRecoveryAction> {
- match self {
- Self::Io { .. }
- | Self::EventStore { .. }
- | Self::Outbox { .. }
- | Self::PrivateStore { .. }
- | Self::StudioStore { .. }
- | Self::Projection { .. } => vec![RadrootsSdkRecoveryAction::InspectLocalStores],
- Self::GeoNames { kind, .. } => match kind {
- RadrootsSdkGeoNamesErrorKind::Configuration => {
- vec![RadrootsSdkRecoveryAction::ConfigureGeoNamesCache]
- }
- RadrootsSdkGeoNamesErrorKind::Download => {
- vec![RadrootsSdkRecoveryAction::RetryGeoNamesDownload]
- }
- RadrootsSdkGeoNamesErrorKind::Cache
- | RadrootsSdkGeoNamesErrorKind::Integrity
- | RadrootsSdkGeoNamesErrorKind::Schema => {
- vec![RadrootsSdkRecoveryAction::InspectGeoNamesAsset]
- }
- RadrootsSdkGeoNamesErrorKind::Lookup => vec![RadrootsSdkRecoveryAction::FixRequest],
- },
- Self::UnauthorizedActor { .. }
- | Self::SignerPubkeyMismatch { .. }
- | Self::SignerRequestRejected { .. }
- | Self::Authority { .. } => vec![RadrootsSdkRecoveryAction::SelectAuthorizedActor],
- Self::SignerUnavailable { .. } | Self::SignerReturnedEventDrift { .. } => {
- vec![RadrootsSdkRecoveryAction::ConfigureSigner]
- }
- Self::EmptyTransportTargets { .. }
- | Self::TransportTargetLimitExceeded { .. }
- | Self::InvalidRelayUrl { .. } => {
- vec![RadrootsSdkRecoveryAction::ConfigureTransportTargets]
- }
- Self::IdempotencyConflict { .. } => {
- vec![RadrootsSdkRecoveryAction::RetryOperationWithSameIdempotencyKey]
- }
- Self::Trade { .. } => vec![RadrootsSdkRecoveryAction::FixRequest],
- Self::PrivacyPreflight { .. } => vec![RadrootsSdkRecoveryAction::FixRequest],
- Self::UnsupportedProfileSchema { .. } => {
- vec![RadrootsSdkRecoveryAction::InspectLocalStores]
- }
- Self::ProductSyncUnsupported { .. } => {
- vec![RadrootsSdkRecoveryAction::EnableRequiredFeature]
- }
- Self::ReticulumTransportUnavailable { .. } => {
- vec![RadrootsSdkRecoveryAction::ConfigureTransportTargets]
- }
- Self::ProductSyncTransportSetupFailure { .. } | Self::Transport { .. } => {
- vec![RadrootsSdkRecoveryAction::RetryAfterTransportFailure]
- }
- Self::SignerRequestTimedOut { .. } | Self::SignerTransport { .. } => {
- vec![RadrootsSdkRecoveryAction::RetryAfterTransportFailure]
- }
- Self::SignerAuthChallengePending { .. } => {
- vec![RadrootsSdkRecoveryAction::CompleteSignerAuthentication]
- }
- Self::ClockBeforeUnixEpoch
- | Self::TimestampOutOfRange { .. }
- | Self::SignerProtocol { .. }
- | Self::InvalidRequest { .. }
- | Self::ListingEdit { .. }
- | Self::ListingValidation { .. }
- | Self::ListingMutation { .. } => vec![RadrootsSdkRecoveryAction::FixRequest],
- }
- }
-
- pub fn detail_json(&self) -> Value {
- let detail = match self {
- Self::Io { path, message } => {
- json!({ "path": path.display().to_string(), "message": message })
- }
- Self::ClockBeforeUnixEpoch => json!({}),
- Self::TimestampOutOfRange { value } => json!({ "value": value }),
- Self::UnauthorizedActor { operation, reason } => {
- json!({ "operation": operation, "reason": reason })
- }
- Self::SignerPubkeyMismatch {
- operation,
- expected_pubkey_prefix,
- signer_pubkey_prefix,
- } => json!({
- "operation": operation,
- "expected_pubkey_prefix": expected_pubkey_prefix,
- "signer_pubkey_prefix": signer_pubkey_prefix
- }),
- Self::SignerUnavailable { mode, reason }
- | Self::SignerRequestRejected { mode, reason }
- | Self::SignerTransport { mode, reason }
- | Self::SignerProtocol { mode, reason } => {
- json!({ "mode": mode, "reason": reason })
- }
- Self::SignerRequestTimedOut { mode } => json!({ "mode": mode }),
- Self::SignerAuthChallengePending { mode, auth_url } => {
- json!({ "mode": mode, "auth_url": auth_url })
- }
- Self::SignerReturnedEventDrift { operation, reason } => {
- json!({ "operation": operation, "reason": reason })
- }
- Self::EmptyTransportTargets { operation } => json!({ "operation": operation }),
- Self::TransportTargetLimitExceeded { max, actual } => {
- json!({ "max": max, "actual": actual })
- }
- Self::InvalidRelayUrl { url, reason } => json!({ "url": url, "reason": reason }),
- Self::IdempotencyConflict {
- operation_kind,
- expected_pubkey_prefix,
- existing_digest_prefix,
- new_digest_prefix,
- } => json!({
- "operation_kind": operation_kind,
- "expected_pubkey_prefix": expected_pubkey_prefix,
- "existing_digest_prefix": existing_digest_prefix,
- "new_digest_prefix": new_digest_prefix
- }),
- Self::Trade {
- kind,
- operation,
- message,
- } => json!({
- "kind": kind,
- "operation": operation,
- "message": message
- }),
- Self::PrivacyPreflight {
- operation,
- status,
- fields,
- } => json!({
- "operation": operation,
- "status": status,
- "fields": fields
- }),
- Self::ProductSyncUnsupported {
- operation,
- required_feature,
- } => json!({ "operation": operation, "required_feature": required_feature }),
- Self::ReticulumTransportUnavailable {
- operation,
- endpoint_uri,
- behavior,
- } => json!({
- "operation": operation,
- "endpoint_uri": endpoint_uri,
- "behavior": behavior.as_str()
- }),
- Self::ListingValidation { kind, message } => {
- json!({ "kind": kind, "message": message })
- }
- Self::ProductSyncTransportSetupFailure { message }
- | Self::Authority { message }
- | Self::EventStore { message }
- | Self::InvalidRequest { message }
- | Self::ListingEdit { message }
- | Self::ListingMutation { message }
- | Self::Outbox { message }
- | Self::PrivateStore { message }
- | Self::StudioStore { message }
- | Self::Transport { message }
- | Self::Projection { message } => json!({ "message": message }),
- Self::UnsupportedProfileSchema { path, message } => {
- json!({ "path": path.display().to_string(), "message": message })
- }
- Self::GeoNames { kind, message } => json!({ "kind": kind, "message": message }),
- };
- json!({
- "code": self.code(),
- "class": self.class(),
- "retryable": self.retryable(),
- "message": self.to_string(),
- "recovery_actions": self.recovery_actions(),
- "detail": detail
- })
- }
-
- pub(crate) fn empty_transport_targets(operation: impl Into<String>) -> Self {
- Self::EmptyTransportTargets {
- operation: operation.into(),
- }
- }
-
- pub(crate) fn transport_target_limit_exceeded(max: usize, actual: usize) -> Self {
- Self::TransportTargetLimitExceeded { max, actual }
- }
-
- pub(crate) fn invalid_relay_url(url: impl Into<String>, reason: impl Into<String>) -> Self {
- Self::InvalidRelayUrl {
- url: redacted_relay_url(url.into()),
- reason: reason.into(),
- }
- }
-
- pub(crate) fn missing_geonames_config() -> Self {
- Self::GeoNames {
- kind: RadrootsSdkGeoNamesErrorKind::Configuration,
- message: "GeoNames cache root is not configured".to_owned(),
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl fmt::Display for RadrootsSdkError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Io { path, message } => {
- write!(f, "sdk storage path `{}` failed: {message}", path.display())
- }
- Self::ClockBeforeUnixEpoch => f.write_str("sdk clock is before the Unix epoch"),
- Self::TimestampOutOfRange { value } => {
- write!(
- f,
- "sdk timestamp {value} exceeds Nostr u32 created_at range"
- )
- }
- Self::UnauthorizedActor { operation, reason } => {
- write!(f, "sdk unauthorized actor for {operation}: {reason}")
- }
- Self::SignerPubkeyMismatch {
- operation,
- expected_pubkey_prefix,
- signer_pubkey_prefix,
- } => write!(
- f,
- "sdk signer pubkey mismatch for {operation}: expected_pubkey_prefix={expected_pubkey_prefix}, signer_pubkey_prefix={signer_pubkey_prefix}"
- ),
- Self::SignerUnavailable { mode, reason } => {
- write!(f, "sdk {mode} signer unavailable: {reason}")
- }
- Self::SignerRequestRejected { mode, reason } => {
- write!(f, "sdk {mode} signer rejected request: {reason}")
- }
- Self::SignerRequestTimedOut { mode } => {
- write!(f, "sdk {mode} signer request timed out")
- }
- Self::SignerAuthChallengePending { mode, auth_url } => match auth_url {
- Some(auth_url) => {
- write!(f, "sdk {mode} signer requires authentication at {auth_url}")
- }
- None => write!(f, "sdk {mode} signer requires authentication"),
- },
- Self::SignerTransport { mode, reason } => {
- write!(f, "sdk {mode} signer transport error: {reason}")
- }
- Self::SignerProtocol { mode, reason } => {
- write!(f, "sdk {mode} signer protocol error: {reason}")
- }
- Self::SignerReturnedEventDrift { operation, reason } => {
- write!(
- f,
- "sdk signer returned event drift for {operation}: {reason}"
- )
- }
- Self::EmptyTransportTargets { operation } => {
- write!(f, "sdk empty transport targets for {operation}")
- }
- Self::TransportTargetLimitExceeded { max, actual } => {
- write!(
- f,
- "sdk transport target limit exceeded: max={max}, actual={actual}"
- )
- }
- Self::InvalidRelayUrl { url, reason } => {
- write!(f, "sdk invalid relay URL `{url}`: {reason}")
- }
- Self::IdempotencyConflict {
- operation_kind,
- expected_pubkey_prefix,
- existing_digest_prefix,
- new_digest_prefix,
- } => write!(
- f,
- "sdk idempotency conflict for {operation_kind}: expected_pubkey_prefix={expected_pubkey_prefix}, existing_digest_prefix={existing_digest_prefix}, new_digest_prefix={new_digest_prefix}"
- ),
- Self::Trade {
- kind,
- operation,
- message,
- } => write!(f, "sdk trade error for {operation} ({kind:?}): {message}"),
- Self::PrivacyPreflight {
- operation,
- status,
- fields,
- } => write!(
- f,
- "sdk privacy preflight failed for {operation}: status={status:?}, field_count={}",
- fields.len()
- ),
- Self::ProductSyncUnsupported {
- operation,
- required_feature,
- } => write!(
- f,
- "sdk product sync operation {operation} requires feature `{required_feature}`"
- ),
- Self::ReticulumTransportUnavailable {
- operation,
- endpoint_uri,
- behavior,
- } => write!(
- f,
- "sdk product sync operation {operation} cannot deliver through Reticulum endpoint `{endpoint_uri}` with behavior `{}`",
- behavior.as_str()
- ),
- Self::ProductSyncTransportSetupFailure { message } => {
- write!(f, "sdk product sync transport setup failed: {message}")
- }
- Self::Authority { message } => write!(f, "sdk authority error: {message}"),
- Self::EventStore { message } => write!(f, "sdk event store error: {message}"),
- Self::InvalidRequest { message } => write!(f, "sdk invalid request: {message}"),
- Self::UnsupportedProfileSchema { path, message } => write!(
- f,
- "sdk unsupported profile schema at `{}`: {message}",
- path.display()
- ),
- Self::ListingEdit { message } => write!(f, "sdk listing edit error: {message}"),
- Self::ListingValidation { kind, message } => {
- write!(f, "sdk listing validation error ({kind:?}): {message}")
- }
- Self::ListingMutation { message } => {
- write!(f, "sdk listing mutation error: {message}")
- }
- Self::Outbox { message } => write!(f, "sdk outbox error: {message}"),
- Self::PrivateStore { message } => write!(f, "sdk private store error: {message}"),
- Self::StudioStore { message } => write!(f, "sdk studio store error: {message}"),
- Self::GeoNames { kind, message } => {
- write!(f, "sdk GeoNames {kind:?} error: {message}")
- }
- Self::Transport { message } => {
- write!(f, "sdk transport error: {message}")
- }
- Self::Projection { message } => write!(f, "sdk projection error: {message}"),
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl std::error::Error for RadrootsSdkError {}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_signing::Error> for RadrootsSdkError {
- fn from(error: radroots_signing::Error) -> Self {
- use radroots_signing::error::Kind;
-
- match error.kind() {
- Kind::AuthorizationDenied => Self::UnauthorizedActor {
- operation: "event signing".to_owned(),
- reason: "actor or signer is not authorized for the frozen draft".to_owned(),
- },
- Kind::SignerCapabilityMissing => Self::SignerUnavailable {
- mode: "configured".to_owned(),
- reason: error.to_string(),
- },
- Kind::SignerUnavailable => Self::SignerUnavailable {
- mode: "configured".to_owned(),
- reason: error.to_string(),
- },
- Kind::SignerRejected => Self::SignerRequestRejected {
- mode: "configured".to_owned(),
- reason: error.to_string(),
- },
- Kind::SignerTimeout | Kind::DeadlineExceeded => Self::SignerRequestTimedOut {
- mode: "configured".to_owned(),
- },
- Kind::SignerCancelled => Self::SignerRequestRejected {
- mode: "configured".to_owned(),
- reason: error.to_string(),
- },
- Kind::SignerOutputInvalid => Self::SignerReturnedEventDrift {
- operation: "event signing".to_owned(),
- reason: error.to_string(),
- },
- Kind::InvalidArgument | Kind::InternalError => Self::Authority {
- message: error.to_string(),
- },
- _ => Self::Authority {
- message: error.to_string(),
- },
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_event_store::RadrootsEventStoreError> for RadrootsSdkError {
- fn from(error: radroots_event_store::RadrootsEventStoreError) -> Self {
- Self::EventStore {
- message: error.to_string(),
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_geocoder::GeocoderError> for RadrootsSdkError {
- fn from(error: radroots_geocoder::GeocoderError) -> Self {
- let kind = match &error {
- radroots_geocoder::GeocoderError::InvalidAssetUrl { .. }
- | radroots_geocoder::GeocoderError::InvalidAssetHost { .. } => {
- RadrootsSdkGeoNamesErrorKind::Configuration
- }
- radroots_geocoder::GeocoderError::AssetDownload { .. } => {
- RadrootsSdkGeoNamesErrorKind::Download
- }
- radroots_geocoder::GeocoderError::Io(_)
- | radroots_geocoder::GeocoderError::Sqlite(_)
- | radroots_geocoder::GeocoderError::SqliteConnectionLockUnavailable
- | radroots_geocoder::GeocoderError::AssetLockUnavailable { .. } => {
- RadrootsSdkGeoNamesErrorKind::Cache
- }
- radroots_geocoder::GeocoderError::InvalidAssetSchema { .. } => {
- RadrootsSdkGeoNamesErrorKind::Schema
- }
- radroots_geocoder::GeocoderError::InvalidAssetLength { .. }
- | radroots_geocoder::GeocoderError::InvalidAssetSha256 { .. }
- | radroots_geocoder::GeocoderError::InvalidAssetSqlite { .. }
- | radroots_geocoder::GeocoderError::InvalidAssetIntegrity { .. } => {
- RadrootsSdkGeoNamesErrorKind::Integrity
- }
- radroots_geocoder::GeocoderError::CountryCenterNotFound { .. } => {
- RadrootsSdkGeoNamesErrorKind::Lookup
- }
- };
- Self::GeoNames {
- kind,
- message: error.to_string(),
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_trade::operational_listing::RadrootsOperationalListingEditError>
- for RadrootsSdkError
-{
- fn from(
- error: radroots_trade::operational_listing::RadrootsOperationalListingEditError,
- ) -> Self {
- match error {
- radroots_trade::operational_listing::RadrootsOperationalListingEditError::InvalidModel(error) => Self::ListingValidation {
- kind: RadrootsSdkListingValidationErrorKind::from(&error),
- message: error.to_string(),
- },
- error => Self::ListingEdit {
- message: error.to_string(),
- },
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_trade::operational_listing::RadrootsOperationalListingMutationError>
- for RadrootsSdkError
-{
- fn from(
- error: radroots_trade::operational_listing::RadrootsOperationalListingMutationError,
- ) -> Self {
- Self::ListingMutation {
- message: error.to_string(),
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_outbox::RadrootsOutboxError> for RadrootsSdkError {
- fn from(error: radroots_outbox::RadrootsOutboxError) -> Self {
- match error {
- radroots_outbox::RadrootsOutboxError::EmptyDeliveryTargets => {
- Self::empty_transport_targets("outbox enqueue")
- }
- radroots_outbox::RadrootsOutboxError::IdempotencyConflict {
- operation_kind,
- expected_pubkey,
- existing_digest,
- new_digest,
- ..
- } => Self::IdempotencyConflict {
- operation_kind,
- expected_pubkey_prefix: redacted_prefix(expected_pubkey.as_str()),
- existing_digest_prefix: redacted_prefix(existing_digest.as_str()),
- new_digest_prefix: redacted_prefix(new_digest.as_str()),
- },
- error => Self::Outbox {
- message: error.to_string(),
- },
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_transport::RadrootsTransportError> for RadrootsSdkError {
- fn from(error: radroots_transport::RadrootsTransportError) -> Self {
- match error {
- radroots_transport::RadrootsTransportError::EmptyTargetSet => {
- Self::empty_transport_targets("transport target set")
- }
- error => Self::Transport {
- message: error.to_string(),
- },
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-impl From<radroots_transport_nostr::RadrootsRelayTransportError> for RadrootsSdkError {
- fn from(error: radroots_transport_nostr::RadrootsRelayTransportError) -> Self {
- match error {
- radroots_transport_nostr::RadrootsRelayTransportError::RelayUrlParse {
- url,
- reason,
- } => Self::invalid_relay_url(url, reason),
- radroots_transport_nostr::RadrootsRelayTransportError::WsRequiresLocalhostPolicy {
- url,
- } => Self::invalid_relay_url(url, "ws relay URL requires localhost policy"),
- radroots_transport_nostr::RadrootsRelayTransportError::UnsupportedRelayScheme {
- url,
- scheme,
- } => Self::invalid_relay_url(url, format!("unsupported scheme `{scheme}`")),
- radroots_transport_nostr::RadrootsRelayTransportError::RelayUrlUserinfo { url } => {
- Self::invalid_relay_url(url, "relay URL must not include userinfo")
- }
- radroots_transport_nostr::RadrootsRelayTransportError::EmptyRelayHost { url } => {
- Self::invalid_relay_url(url, "relay URL must include a host")
- }
- radroots_transport_nostr::RadrootsRelayTransportError::RelayUrlQueryOrFragment {
- url,
- } => Self::invalid_relay_url(url, "relay URL must not include query or fragment"),
- radroots_transport_nostr::RadrootsRelayTransportError::RelayUrlForbiddenDestination {
- url,
- reason,
- } => Self::invalid_relay_url(url, reason),
- radroots_transport_nostr::RadrootsRelayTransportError::RelayUrlResolvedForbiddenDestination {
- url,
- address,
- reason,
- } => Self::invalid_relay_url(
- url,
- format!("relay URL resolved to forbidden address `{address}`: {reason}"),
- ),
- radroots_transport_nostr::RadrootsRelayTransportError::EmptyTargetSet => {
- Self::empty_transport_targets("nostr relay publish")
- }
- #[cfg(feature = "runtime")]
- radroots_transport_nostr::RadrootsRelayTransportError::Outbox(error) => error.into(),
- error => Self::Transport {
- message: error.to_string(),
- },
- }
- }
-}
-
-#[cfg(feature = "runtime")]
-fn redacted_prefix(value: &str) -> String {
- value.chars().take(12).collect()
-}
-
-#[cfg(feature = "runtime")]
-fn redacted_relay_url(value: String) -> String {
- let redacted = redact_query_or_fragment(value.as_str());
- let Some((scheme, rest)) = redacted.split_once("://") else {
- return redacted;
- };
- let authority = rest.split('/').next().unwrap_or(rest);
- let Some((_, after_userinfo)) = authority.rsplit_once('@') else {
- return redacted;
- };
- let path = rest.strip_prefix(authority).unwrap_or_default();
- format!("{scheme}://<redacted>@{after_userinfo}{path}")
-}
-
-#[cfg(feature = "runtime")]
-fn redact_query_or_fragment(value: &str) -> String {
- let Some((index, marker)) = value.char_indices().find_map(|(index, character)| {
- matches!(character, '?' | '#').then_some((index, character))
- }) else {
- return value.to_owned();
- };
- format!("{}{}<redacted>", &value[..index], marker)
-}
-
-#[cfg(test)]
-#[path = "../tests/unit/error_tests.rs"]
-mod tests;
+//! SDK-owned error boundary.
diff --git a/crates/sdk/src/farm.rs b/crates/sdk/src/farm.rs
@@ -1,9 +1 @@
-pub use radroots_event::farm::*;
-
-pub use radroots_event_codec::encode::EventEncodeError;
-
-use radroots_event::wire::Nip01EventWireParts;
-
-pub fn build_draft(farm: &Farm) -> Result<Nip01EventWireParts, EventEncodeError> {
- radroots_event_codec::encode::farm::to_wire_parts(farm)
-}
+//! Farm product operations.
diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs
@@ -1,201 +1,18 @@
-#![cfg_attr(not(feature = "std"), no_std)]
-#![forbid(unsafe_code)]
+//! Host-neutral asynchronous client engine for Radroots.
+//!
+//! This checkpoint establishes the final package and module ownership
+//! boundary. Client behavior is introduced through the ordered SDK refactor.
-#[cfg(not(feature = "std"))]
-extern crate alloc;
+#![forbid(unsafe_code)]
-#[cfg(feature = "runtime")]
-mod actor_json;
-#[cfg(any(
- feature = "radrootsd-execution",
- feature = "transport-nostr-client",
- feature = "signer-adapters"
-))]
-pub mod adapters;
-#[cfg(feature = "runtime")]
-mod error;
-#[cfg(feature = "runtime")]
-mod farm;
-#[cfg(feature = "runtime")]
-mod farms_runtime;
-#[cfg(all(test, feature = "runtime", feature = "signer-adapters"))]
-#[path = "../tests/support/fixture_signer.rs"]
-pub(crate) mod fixture_signer;
-#[cfg(feature = "runtime")]
-mod geonames;
-#[cfg(feature = "runtime")]
-mod idempotency;
-#[cfg(feature = "identity-models")]
-pub mod identity;
-#[cfg(feature = "knowledge")]
-pub mod knowledge;
-#[cfg(feature = "runtime")]
-mod listings_runtime;
-#[cfg(feature = "runtime")]
-mod privacy;
-#[cfg(feature = "runtime")]
-mod private_store;
-#[cfg(feature = "runtime")]
-mod product_clients;
-#[cfg(feature = "runtime")]
-mod runtime;
-#[cfg(all(test, feature = "runtime"))]
-#[path = "../tests/support/serializer_failure.rs"]
-pub(crate) mod serializer_failure;
-#[cfg(all(feature = "runtime", feature = "signer-adapters"))]
-mod signer_provider;
-#[cfg(feature = "runtime")]
-mod studio_store;
-#[cfg(feature = "runtime")]
-mod sync_runtime;
-#[cfg(feature = "runtime")]
-mod trade_runtime;
-#[cfg(feature = "runtime")]
+pub mod capability;
+pub mod client;
+pub mod diagnostics;
+pub mod error;
+pub mod farm;
+pub mod listing;
+pub mod signing;
+pub mod storage;
+pub mod sync;
+pub mod trade;
pub mod transport;
-#[cfg(feature = "runtime")]
-mod workflow_runtime;
-
-#[cfg(feature = "runtime")]
-pub use crate::error::{
- RADROOTS_SDK_ERROR_CATALOG, RadrootsSdkError, RadrootsSdkErrorCatalogEntry,
- RadrootsSdkErrorClass, RadrootsSdkGeoNamesErrorKind, RadrootsSdkListingValidationErrorKind,
- RadrootsSdkRecoveryAction, RadrootsSdkTradeErrorKind, radroots_sdk_error_catalog,
-};
-#[cfg(feature = "runtime")]
-pub use crate::farms_runtime::{
- FARM_PUBLISH_OPERATION_KIND, FarmEnqueuePublishRequest, FarmEnqueueReceipt,
- FarmPreparePublishRequest, FarmPrivateLocationClearReceipt, FarmPrivateLocationClearRequest,
- FarmPrivateLocationInput, FarmPrivateLocationLookupCandidate, FarmPrivateLocationLookupReceipt,
- FarmPrivateLocationReceipt, FarmPrivateLocationSetRequest, FarmPrivateLocationSetResult,
- FarmPrivateLocationUpsertRequest, FarmPublishPlan, SdkExactLocation, SdkPublicLocality,
-};
-#[cfg(feature = "runtime")]
-pub use crate::geonames::{
- GEONAMES_1_0_ASSET, GEONAMES_ASSET_BYTE_SIZE, GEONAMES_ASSET_FILE_NAME, GEONAMES_ASSET_HOST,
- GEONAMES_ASSET_SHA256, GEONAMES_ASSET_URL, GEONAMES_ASSET_VERSION, GeoNamesAssetFetcher,
- GeoNamesAssetSpec, GeoNamesAssetState, GeoNamesAssetStatus, GeoNamesBlockingHttpFetcher,
- Geocoder, GeocoderCountryListResult, GeocoderError, GeocoderLocalityCandidate,
- GeocoderLocalityInput, GeocoderLocalityLookup, GeocoderLocalityQuery, GeocoderPoint,
- GeocoderReverseOptions, GeocoderReverseResult, GeocoderStructuredLocalityQuery,
- RadrootsGeoNamesConfig,
-};
-#[cfg(feature = "runtime")]
-pub use crate::idempotency::{
- SDK_IDEMPOTENCY_KEY_MAX_LEN, SdkIdempotencyKey, SdkTradeIdempotencyRecord,
-};
-#[cfg(feature = "knowledge")]
-pub use crate::knowledge::{
- AddressableRef, DraftError, EventDraft, EventEnvelope, EventRef, KIND_FILE_METADATA,
- KIND_KNOWLEDGE_CLAIM, KIND_KNOWLEDGE_FIELD_REPORT, KIND_KNOWLEDGE_RELATION,
- KIND_KNOWLEDGE_REVIEW, KIND_KNOWLEDGE_SOURCE, KIND_WIKI_ARTICLE, KIND_WIKI_MERGE_REQUEST,
- KIND_WIKI_REDIRECT, KNOWLEDGE_CLAIM_CONTRACT_ID, KNOWLEDGE_FIELD_REPORT_CONTRACT_ID,
- KNOWLEDGE_RELATION_CONTRACT_ID, KNOWLEDGE_REVIEW_CONTRACT_ID, KNOWLEDGE_SOURCE_CONTRACT_ID,
- KnowledgeChangeProposal, KnowledgeCitationSpan, KnowledgeClaim, KnowledgeCodec,
- KnowledgeDraftBuilder, KnowledgeEventBuilder, KnowledgeFieldContext, KnowledgeFieldReport,
- KnowledgeLocation, KnowledgeLocationPrecision, KnowledgeNodeRef, KnowledgeObservation,
- KnowledgeObservationValue, KnowledgeRelation, KnowledgeReview, KnowledgeReviewScope,
- KnowledgeReviewScore, KnowledgeReviewTarget, KnowledgeSource, Nip01EventWireParts,
- RADROOTS_CONTRIBUTION_ATTESTATION_SCHEMA, RADROOTS_EVIDENCE_BOUNTY_SCHEMA,
- RADROOTS_KNOWLEDGE_CHANGE_PROPOSAL_SCHEMA, RADROOTS_KNOWLEDGE_CLAIM_SCHEMA,
- RADROOTS_KNOWLEDGE_CONTRACT_MANIFEST_SCHEMA_VERSION, RADROOTS_KNOWLEDGE_FIELD_REPORT_SCHEMA,
- RADROOTS_KNOWLEDGE_RELATION_SCHEMA, RADROOTS_KNOWLEDGE_REVIEW_SCHEMA,
- RADROOTS_KNOWLEDGE_SCHEMA_VERSION, RADROOTS_KNOWLEDGE_SOURCE_SCHEMA,
- RADROOTS_WIKI_D_TAG_MAX_LEN, RadrootsContractValidatedEvent, RadrootsDecodeError,
- RadrootsDecodedEvent, RadrootsEncodeError, RadrootsIdVerifiedEvent,
- RadrootsKnowledgeBuilderError, RadrootsKnowledgeClaimBuilder,
- RadrootsKnowledgeContractManifest, RadrootsKnowledgeContractManifestEntry,
- RadrootsKnowledgeFieldReportBuilder, RadrootsKnowledgeManifestCodecSupport,
- RadrootsKnowledgeManifestDiscriminator, RadrootsKnowledgeManifestTagContract,
- RadrootsKnowledgeRelationBuilder, RadrootsKnowledgeReviewBuilder,
- RadrootsKnowledgeSourceBuilder, RadrootsNip01VerificationError, RadrootsSdkKnowledgeError,
- RadrootsSignatureVerifiedEvent, RadrootsWikiArticleBuilder, RadrootsWikiMergeRequestBuilder,
- RadrootsWikiRedirectBuilder, RightsAssertion, WIKI_ARTICLE_CONTRACT_ID,
- WIKI_MERGE_REQUEST_CONTRACT_ID, WIKI_REDIRECT_CONTRACT_ID, WikiArticle, WikiArticleVersionRef,
- WikiDTagError, WikiMergeRequest, WikiRedirect, build_knowledge_claim_event,
- build_knowledge_field_report_event, build_knowledge_relation_event,
- build_knowledge_review_event, build_knowledge_source_event, build_wiki_article_event,
- build_wiki_merge_request_event, build_wiki_redirect_event, contract_manifest,
- contract_manifest_json, contract_manifest_sha256, normalize_wiki_d_tag,
- prepare_knowledge_claim_draft, prepare_knowledge_field_report_draft,
- prepare_knowledge_relation_draft, prepare_knowledge_review_draft,
- prepare_knowledge_source_draft, prepare_wiki_article_draft, prepare_wiki_merge_request_draft,
- prepare_wiki_redirect_draft, validate_wiki_d_tag, verify_and_decode_radroots_event,
-};
-#[cfg(feature = "runtime")]
-pub use crate::listings_runtime::{
- LISTING_PUBLISH_OPERATION_KIND, ListingEnqueuePublishRequest, ListingEnqueueReceipt,
- ListingPreparePublishRequest, ListingPublishPlan, SdkMutationState,
-};
-#[cfg(feature = "runtime")]
-pub use crate::privacy::{
- PrivacyPreflightConfirmation, PrivacyPreflightReceipt, PrivacyPreflightStatus,
- ProductSensitivityField,
-};
-#[cfg(feature = "runtime")]
-pub use crate::product_clients::{
- FarmsClient, GeoNamesClient, ListingsClient, MarketClient, SyncClient, TradesClient,
-};
-#[cfg(feature = "runtime")]
-pub use crate::runtime::{
- BackupReceipt, BackupRequest, IntegrityReceipt, IntegrityRequest, RadrootsClient,
- RadrootsClientBuilder, RadrootsSdkClock, RadrootsSdkStorageConfig, RadrootsSdkStoragePaths,
- RadrootsSdkTimestamp, RestoreArchive, RestoreReceipt, RestoreRequest, SdkBackupKeyReference,
- SdkBackupManifest, SdkBackupManifestKind, SdkBackupMemberHash, SdkBackupMemberHashes,
- SdkBackupRecoveryManifest, SdkBackupState, SdkBackupVerification, SdkEventStoreStorageStatus,
- SdkOutboxStorageStatus, SdkPrivateStoreStorageStatus, SdkRestoreFinalization, SdkRestoreState,
- SdkSqliteStoreStatus, SdkSqliteWalCheckpointReceipt, SdkSqliteWalStatus, SdkStorageKind,
- SdkStudioStoreStorageStatus, StorageCheckpointReceipt, StorageCheckpointRequest,
- StorageStatusReceipt, StorageStatusRequest,
-};
-#[cfg(all(feature = "runtime", feature = "signer-adapters"))]
-#[doc(hidden)]
-pub use crate::signer_provider::{
- RADROOTS_SDK_MYC_NIP46_DEFAULT_REQUEST_TIMEOUT_MS,
- RADROOTS_SDK_MYC_NIP46_PRODUCT_SIGN_EVENT_KINDS, RadrootsSdkLocalKeySigner,
- RadrootsSdkLocalSignerCapability, RadrootsSdkMycNip46RequestPolicy, RadrootsSdkMycNip46Signer,
- RadrootsSdkNip46ClientKey, RadrootsSdkNip46Transport, RadrootsSdkNip46TransportFuture,
- RadrootsSdkSignReceipt, RadrootsSdkSignRequest, RadrootsSdkSignerCapability,
- RadrootsSdkSignerMode, RadrootsSdkSignerProgress, RadrootsSdkSignerProgressSink,
- RadrootsSdkSignerProvider, RadrootsSdkSignerState, RadrootsSdkSignerStatus,
- radroots_sdk_myc_nip46_product_permission_strings, radroots_sdk_myc_nip46_product_permissions,
-};
-#[cfg(feature = "runtime")]
-pub use crate::sync_runtime::{
- PUSH_OUTBOX_DEFAULT_CLAIM_TTL_MS, PUSH_OUTBOX_DEFAULT_LIMIT,
- PUSH_OUTBOX_DEFAULT_NEXT_ATTEMPT_DELAY_MS, PUSH_OUTBOX_MAX_LIMIT, PushOutboxEventReceipt,
- PushOutboxEventState, PushOutboxReceipt, PushOutboxRequest, PushOutboxTargetOutcomeKind,
- PushOutboxTargetReceipt, PushOutboxTransportOutcomeKind, ReticulumTryNowRequest,
- SYNC_PROJECTION_REFRESH_DEFAULT_LIMIT, SYNC_PROJECTION_REFRESH_MAX_LIMIT, SdkRelayAuthPolicy,
- SyncEventStoreStatus, SyncOutboxStatus, SyncProjectionRefreshReceipt,
- SyncProjectionRefreshRequest, SyncStatusReceipt, SyncStatusRequest, SyncStatusSource,
- SyncTransportOperationCapabilitiesSummary, SyncTransportProfileSummary,
- SyncTransportStatusSummary, SyncTransportTargetSummary,
-};
-#[cfg(feature = "runtime")]
-pub use crate::trade_runtime::{
- CancelTradeRequest, DecideCandidateRequest, EvidenceRefreshReceipt, EvidenceView,
- GetTradeRequest, InspectEvidenceRequest, ListTradesRequest, Page, ProposeRevisionRequest,
- RefreshTradeEvidenceRequest, ResumeOperationRequest, SubmitProposalRequest,
- TRADE_CANCEL_OPERATION_KIND, TRADE_DECIDE_CANDIDATE_OPERATION_KIND,
- TRADE_PROPOSE_REVISION_OPERATION_KIND, TRADE_QUERY_DEFAULT_LIMIT, TRADE_QUERY_MAX_LIMIT,
- TRADE_RESUME_OPERATION_KIND, TRADE_RUNTIME_CAPABILITY_API_VERSION,
- TRADE_RUNTIME_PRIVATE_STORAGE_PROFILE_ID, TRADE_RUNTIME_PROTOCOL_PROFILE_ID,
- TRADE_RUNTIME_STORAGE_PROFILE_ID, TRADE_RUNTIME_WIRE_PROFILE_ID,
- TRADE_SUBMIT_PROPOSAL_OPERATION_KIND, TradeCommandLifecycleState, TradeCommandReceipt,
- TradeCommandService, TradeCoreMvpCapabilityReport, TradeListAnyOf, TradeListFilter,
- TradeListSort, TradeOptionalIntegrationCapabilityReport, TradePrivateArtifactDeleteReceipt,
- TradePrivateArtifactDeleteRequest, TradePrivateArtifactKind, TradePrivateArtifactOpenReceipt,
- TradePrivateArtifactOpenRequest, TradePrivateArtifactSealReceipt,
- TradePrivateArtifactSealRequest, TradePrivateTermsAvailabilityView,
- TradeProtocolCapabilityReport, TradeQueryService, TradeRuntimeCapabilityReport,
- TradeStatusView, TradeStorageCapabilityReport, TradeSummaryView,
-};
-#[cfg(feature = "runtime")]
-pub use crate::transport::{
- MeshScopeId, MultiTargetProfile, NostrProfile, NostrRelayUrlPolicy, PublishMode,
- RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryTargetStatus,
- RadrootsTransportOutcome, RadrootsTransportSatisfactionClass, RadrootsTransportTargetReceipt,
- RadrootsdExecutionAuth, RadrootsdExecutionProfile, ReticulumAgentEndpoint, ReticulumBehavior,
- ReticulumProfile, SDK_TRANSPORT_TARGET_MAX_COUNT, SatisfactionPolicy, TargetPolicy, TargetSet,
- TransportId, TransportProfile, TransportReceipt,
-};
diff --git a/crates/sdk/src/listing.rs b/crates/sdk/src/listing.rs
@@ -0,0 +1 @@
+//! Listing product operations.
diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs
@@ -0,0 +1 @@
+//! Signing capability composition.
diff --git a/crates/sdk/src/storage.rs b/crates/sdk/src/storage.rs
@@ -0,0 +1 @@
+//! Storage capability composition.
diff --git a/crates/sdk/src/sync.rs b/crates/sdk/src/sync.rs
@@ -0,0 +1 @@
+//! Synchronization capability composition.
diff --git a/crates/sdk/src/trade.rs b/crates/sdk/src/trade.rs
@@ -0,0 +1 @@
+//! Trade commands and queries.
diff --git a/crates/sdk/src/transport.rs b/crates/sdk/src/transport.rs
@@ -1,773 +1 @@
-use crate::RadrootsSdkError;
-use radroots_transport::target::{TargetFingerprint, TargetScope, TargetSet as TransportTargetSet};
-use radroots_transport::{
- RadrootsTransportCapabilityAvailability, RadrootsTransportCapabilityMaturity,
- RadrootsTransportImplementationState, RadrootsTransportSatisfactionPolicy,
- RadrootsTransportStatus, Target,
-};
-use radroots_transport_nostr::{RadrootsRelayUrlPolicy, RelayUrl};
-use radroots_transport_reticulum::{
- RADROOTS_RETICULUM_ENDPOINT_URI, RADROOTS_RETICULUM_SCOPE_ID,
- RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE,
-};
-use serde::ser::{SerializeStruct, Serializer};
-use std::collections::BTreeSet;
-
-pub use radroots_transport::{
- RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryTargetStatus,
- RadrootsTransportOutcome, RadrootsTransportSatisfactionClass, RadrootsTransportTargetReceipt,
- TransportId,
-};
-
-pub const SDK_TRANSPORT_TARGET_MAX_COUNT: usize = 20;
-pub const RETICULUM_AGENT_ENDPOINT_PREFIX: &str = "reticulum-agent:";
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum PublishMode {
- DryRun,
- EnqueueOnly,
- EnqueueAndPublish,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum SatisfactionPolicy {
- NoWait,
- AnyAccepted,
- AllAccepted,
- QuorumAccepted {
- threshold: u16,
- },
- AnyDelivered,
- AllDelivered,
- QuorumDelivered {
- threshold: u16,
- },
- RequiredAcceptedTargets {
- target_fingerprints: Vec<TargetFingerprint>,
- },
- RequiredDeliveredTargets {
- target_fingerprints: Vec<TargetFingerprint>,
- },
-}
-
-impl SatisfactionPolicy {
- pub fn quorum_accepted(threshold: u16) -> Result<Self, RadrootsSdkError> {
- validate_satisfaction_threshold(threshold)?;
- Ok(Self::QuorumAccepted { threshold })
- }
-
- pub fn quorum_delivered(threshold: u16) -> Result<Self, RadrootsSdkError> {
- validate_satisfaction_threshold(threshold)?;
- Ok(Self::QuorumDelivered { threshold })
- }
-
- pub fn required_accepted_targets<I, S>(targets: I) -> Result<Self, RadrootsSdkError>
- where
- I: IntoIterator<Item = S>,
- S: AsRef<str>,
- {
- Ok(Self::RequiredAcceptedTargets {
- target_fingerprints: required_target_fingerprints(targets)?,
- })
- }
-
- pub fn required_delivered_targets<I, S>(targets: I) -> Result<Self, RadrootsSdkError>
- where
- I: IntoIterator<Item = S>,
- S: AsRef<str>,
- {
- Ok(Self::RequiredDeliveredTargets {
- target_fingerprints: required_target_fingerprints(targets)?,
- })
- }
-
- pub fn is_no_wait(&self) -> bool {
- matches!(self, Self::NoWait)
- }
-
- pub(crate) fn transport_satisfaction_policy(
- &self,
- ) -> Result<RadrootsTransportSatisfactionPolicy, RadrootsSdkError> {
- Ok(match self {
- Self::NoWait => RadrootsTransportSatisfactionPolicy::no_wait(),
- Self::AnyAccepted => RadrootsTransportSatisfactionPolicy::any_accepted(),
- Self::AllAccepted => RadrootsTransportSatisfactionPolicy::all_accepted(),
- Self::QuorumAccepted { threshold } => {
- RadrootsTransportSatisfactionPolicy::quorum_accepted(*threshold)
- }
- Self::AnyDelivered => RadrootsTransportSatisfactionPolicy::any_delivered(),
- Self::AllDelivered => RadrootsTransportSatisfactionPolicy::all_delivered(),
- Self::QuorumDelivered { threshold } => {
- RadrootsTransportSatisfactionPolicy::quorum_delivered(*threshold)
- }
- Self::RequiredAcceptedTargets {
- target_fingerprints,
- } => RadrootsTransportSatisfactionPolicy::required_targets(
- RadrootsTransportSatisfactionClass::Accepted,
- target_fingerprints.clone(),
- )?,
- Self::RequiredDeliveredTargets {
- target_fingerprints,
- } => RadrootsTransportSatisfactionPolicy::required_targets(
- RadrootsTransportSatisfactionClass::Delivered,
- target_fingerprints.clone(),
- )?,
- })
- }
-}
-
-fn validate_satisfaction_threshold(threshold: u16) -> Result<(), RadrootsSdkError> {
- if threshold == 0 {
- return Err(RadrootsSdkError::InvalidRequest {
- message: "satisfaction policy threshold must require at least one target".to_owned(),
- });
- }
- Ok(())
-}
-
-fn required_target_fingerprints<I, S>(
- targets: I,
-) -> Result<Vec<TargetFingerprint>, RadrootsSdkError>
-where
- I: IntoIterator<Item = S>,
- S: AsRef<str>,
-{
- let fingerprints = targets
- .into_iter()
- .map(|target| TargetFingerprint::parse(target.as_ref()))
- .collect::<Result<Vec<_>, _>>()?;
- RadrootsTransportSatisfactionPolicy::required_targets(
- RadrootsTransportSatisfactionClass::Accepted,
- fingerprints.clone(),
- )?;
- Ok(fingerprints)
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum NostrRelayUrlPolicy {
- Public,
- Localhost,
-}
-
-impl NostrRelayUrlPolicy {
- pub(crate) fn nostr_transport_policy(self) -> RadrootsRelayUrlPolicy {
- match self {
- Self::Public => RadrootsRelayUrlPolicy::Public,
- Self::Localhost => RadrootsRelayUrlPolicy::Localhost,
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-#[non_exhaustive]
-pub enum TargetPolicy {
- Explicit(TargetSet),
- DefaultProfile,
- LocalOnly,
- MeshScope(MeshScopeId),
-}
-
-impl TargetPolicy {
- pub fn explicit(targets: TargetSet) -> Self {
- Self::Explicit(targets)
- }
-
- pub fn try_nostr_relays<I, S>(
- relays: I,
- url_policy: NostrRelayUrlPolicy,
- ) -> Result<Self, RadrootsSdkError>
- where
- I: IntoIterator<Item = S>,
- S: AsRef<str>,
- {
- Ok(Self::Explicit(TargetSet::nostr_relays(relays, url_policy)?))
- }
-
- pub fn default_profile() -> Self {
- Self::DefaultProfile
- }
-
- pub fn local_only() -> Self {
- Self::LocalOnly
- }
-
- pub fn mesh_scope(scope: MeshScopeId) -> Self {
- Self::MeshScope(scope)
- }
-}
-
-impl serde::Serialize for TargetPolicy {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- match self {
- Self::Explicit(targets) => {
- let mut state = serializer.serialize_struct("TargetPolicy", 3)?;
- state.serialize_field("kind", "explicit")?;
- state.serialize_field("targets", targets.targets())?;
- state.serialize_field("canonical_targets", targets.canonical_targets())?;
- state.end()
- }
- Self::DefaultProfile => {
- let mut state = serializer.serialize_struct("TargetPolicy", 1)?;
- state.serialize_field("kind", "default_profile")?;
- state.end()
- }
- Self::LocalOnly => {
- let mut state = serializer.serialize_struct("TargetPolicy", 1)?;
- state.serialize_field("kind", "local_only")?;
- state.end()
- }
- Self::MeshScope(scope) => {
- let mut state = serializer.serialize_struct("TargetPolicy", 2)?;
- state.serialize_field("kind", "mesh_scope")?;
- state.serialize_field("scope", scope)?;
- state.end()
- }
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(transparent)]
-pub struct MeshScopeId(TargetScope);
-
-impl MeshScopeId {
- pub fn parse(raw: impl AsRef<str>) -> Result<Self, RadrootsSdkError> {
- Ok(Self(TargetScope::parse(raw)?))
- }
-
- pub fn local_reticulum() -> Self {
- Self(TargetScope::parse(RADROOTS_RETICULUM_SCOPE_ID).expect("Reticulum scope"))
- }
-
- pub fn as_str(&self) -> &str {
- self.0.as_str()
- }
-
- pub(crate) fn transport_scope(&self) -> TargetScope {
- self.0.clone()
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct TargetSet {
- targets: Vec<Target>,
- canonical_targets: Vec<String>,
-}
-
-impl TargetSet {
- pub fn nostr_relays<I, S>(
- relays: I,
- policy: NostrRelayUrlPolicy,
- ) -> Result<Self, RadrootsSdkError>
- where
- I: IntoIterator<Item = S>,
- S: AsRef<str>,
- {
- let mut targets = Vec::new();
- for relay in relays {
- let normalized = normalized_nostr_relay_url(relay.as_ref(), policy)?;
- targets.push(Target::new(TransportId::NOSTR, normalized)?);
- }
- Self::from_transport_targets(targets)
- }
-
- pub fn transport_targets(targets: Vec<Target>) -> Result<Self, RadrootsSdkError> {
- Self::from_transport_targets(targets)
- }
-
- pub fn targets(&self) -> &[Target] {
- self.targets.as_slice()
- }
-
- pub fn canonical_targets(&self) -> &[String] {
- self.canonical_targets.as_slice()
- }
-
- pub fn transport_target_set(&self) -> Result<TransportTargetSet, RadrootsSdkError> {
- Ok(TransportTargetSet::new(self.targets.clone())?)
- }
-
- pub fn nostr_relay_urls(&self) -> Vec<String> {
- self.targets
- .iter()
- .filter(|target| target.kind() == &TransportId::NOSTR)
- .map(|target| target.uri().as_str().to_owned())
- .collect()
- }
-
- pub fn into_targets(self) -> Vec<Target> {
- self.targets
- }
-
- pub fn len(&self) -> usize {
- self.targets.len()
- }
-
- pub fn is_empty(&self) -> bool {
- self.targets.is_empty()
- }
-
- fn from_transport_targets(targets: Vec<Target>) -> Result<Self, RadrootsSdkError> {
- if targets.is_empty() {
- return Err(RadrootsSdkError::empty_transport_targets(
- "sdk transport target set",
- ));
- }
- if targets.len() > SDK_TRANSPORT_TARGET_MAX_COUNT {
- return Err(RadrootsSdkError::transport_target_limit_exceeded(
- SDK_TRANSPORT_TARGET_MAX_COUNT,
- targets.len(),
- ));
- }
- for target in &targets {
- if target.kind() == &TransportId::RETICULUM
- && target.uri().as_str() != RADROOTS_RETICULUM_ENDPOINT_URI
- {
- return Err(RadrootsSdkError::InvalidRequest {
- message: format!(
- "Reticulum endpoint must be {RADROOTS_RETICULUM_ENDPOINT_URI}"
- ),
- });
- }
- }
- TransportTargetSet::new(targets.clone())?;
- let canonical_targets = targets
- .iter()
- .map(|target| target.fingerprint().to_string())
- .collect::<BTreeSet<_>>()
- .into_iter()
- .collect();
- Ok(Self {
- targets,
- canonical_targets,
- })
- }
-}
-
-impl serde::Serialize for TargetSet {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- let mut state = serializer.serialize_struct("TargetSet", 2)?;
- state.serialize_field("targets", self.targets())?;
- state.serialize_field("canonical_targets", self.canonical_targets())?;
- state.end()
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-pub struct NostrProfile {
- target_set: TargetSet,
-}
-
-impl NostrProfile {
- pub fn new<I, S>(relays: I, policy: NostrRelayUrlPolicy) -> Result<Self, RadrootsSdkError>
- where
- I: IntoIterator<Item = S>,
- S: AsRef<str>,
- {
- Ok(Self {
- target_set: TargetSet::nostr_relays(relays, policy)?,
- })
- }
-
- pub fn target_set(&self) -> &TargetSet {
- &self.target_set
- }
-
- pub fn relay_urls(&self) -> Vec<String> {
- self.target_set.nostr_relay_urls()
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-pub struct ReticulumProfile {
- endpoint_uri: String,
- scope: MeshScopeId,
- agent_endpoint: Option<ReticulumAgentEndpoint>,
- behavior: ReticulumBehavior,
-}
-
-impl ReticulumProfile {
- pub fn deferred_until_implemented() -> Self {
- Self {
- endpoint_uri: RADROOTS_RETICULUM_ENDPOINT_URI.to_owned(),
- scope: MeshScopeId::local_reticulum(),
- agent_endpoint: None,
- behavior: ReticulumBehavior::RejectDeliveryAttempts,
- }
- }
-
- pub fn with_behavior(mut self, behavior: ReticulumBehavior) -> Self {
- self.behavior = behavior;
- self
- }
-
- pub fn endpoint_uri(&self) -> &str {
- self.endpoint_uri.as_str()
- }
-
- pub fn scope(&self) -> &MeshScopeId {
- &self.scope
- }
-
- pub fn agent_endpoint(&self) -> Option<&ReticulumAgentEndpoint> {
- self.agent_endpoint.as_ref()
- }
-
- pub fn with_agent_endpoint(mut self, agent_endpoint: ReticulumAgentEndpoint) -> Self {
- self.agent_endpoint = Some(agent_endpoint);
- self
- }
-
- pub fn with_scope(mut self, scope: MeshScopeId) -> Self {
- self.scope = scope;
- self
- }
-
- pub fn behavior(&self) -> ReticulumBehavior {
- self.behavior
- }
-
- pub fn target_set(&self) -> Result<TargetSet, RadrootsSdkError> {
- if self.endpoint_uri.as_str() != RADROOTS_RETICULUM_ENDPOINT_URI {
- return Err(radroots_transport::RadrootsTransportError::InvalidTargetUri.into());
- }
- TargetSet::transport_targets(vec![Target::new_with_metadata(
- TransportId::RETICULUM,
- self.endpoint_uri.as_str(),
- Some(self.scope.transport_scope()),
- None,
- )?])
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(transparent)]
-pub struct ReticulumAgentEndpoint(String);
-
-impl ReticulumAgentEndpoint {
- pub fn parse(raw: impl AsRef<str>) -> Result<Self, RadrootsSdkError> {
- let uri = raw.as_ref();
- let Some(suffix) = uri.strip_prefix(RETICULUM_AGENT_ENDPOINT_PREFIX) else {
- return Err(RadrootsSdkError::InvalidRequest {
- message: "Reticulum agent endpoint is invalid".to_owned(),
- });
- };
- if uri.is_empty()
- || uri != uri.trim()
- || suffix.is_empty()
- || uri
- .chars()
- .any(|ch| ch.is_ascii_control() || ch.is_ascii_whitespace())
- {
- return Err(RadrootsSdkError::InvalidRequest {
- message: "Reticulum agent endpoint is invalid".to_owned(),
- });
- }
- Ok(Self(uri.to_owned()))
- }
-
- pub fn as_str(&self) -> &str {
- self.0.as_str()
- }
-}
-
-impl Default for ReticulumProfile {
- fn default() -> Self {
- Self::deferred_until_implemented()
- }
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case")]
-#[non_exhaustive]
-pub enum ReticulumBehavior {
- RejectDeliveryAttempts,
- DeferDeliveryPlans,
-}
-
-impl ReticulumBehavior {
- pub fn as_str(self) -> &'static str {
- match self {
- Self::RejectDeliveryAttempts => "reject_delivery_attempts",
- Self::DeferDeliveryPlans => "defer_delivery_plans",
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-pub struct MultiTargetProfile {
- nostr: NostrProfile,
- reticulum: ReticulumProfile,
-}
-
-impl MultiTargetProfile {
- pub fn new(nostr: NostrProfile, reticulum: ReticulumProfile) -> Self {
- Self { nostr, reticulum }
- }
-
- pub fn nostr(&self) -> &NostrProfile {
- &self.nostr
- }
-
- pub fn reticulum(&self) -> &ReticulumProfile {
- &self.reticulum
- }
-}
-
-#[derive(Clone, Default, PartialEq, Eq)]
-pub enum RadrootsdExecutionAuth {
- #[default]
- None,
- BearerToken(String),
-}
-
-impl core::fmt::Debug for RadrootsdExecutionAuth {
- fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- match self {
- Self::None => f.write_str("None"),
- Self::BearerToken(_) => f.write_str("BearerToken(<redacted>)"),
- }
- }
-}
-
-impl serde::Serialize for RadrootsdExecutionAuth {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- let mut state = serializer.serialize_struct("RadrootsdExecutionAuth", 1)?;
- match self {
- Self::None => state.serialize_field("kind", "none")?,
- Self::BearerToken(_) => state.serialize_field("kind", "bearer_token")?,
- }
- state.end()
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-pub struct RadrootsdExecutionProfile {
- endpoint_url: String,
- auth: RadrootsdExecutionAuth,
-}
-
-impl RadrootsdExecutionProfile {
- pub fn new(endpoint_url: impl Into<String>) -> Self {
- Self {
- endpoint_url: endpoint_url.into(),
- auth: RadrootsdExecutionAuth::None,
- }
- }
-
- pub fn with_bearer_token(mut self, token: impl Into<String>) -> Self {
- self.auth = RadrootsdExecutionAuth::BearerToken(token.into());
- self
- }
-
- pub fn endpoint_url(&self) -> &str {
- self.endpoint_url.as_str()
- }
-
- pub fn auth(&self) -> &RadrootsdExecutionAuth {
- &self.auth
- }
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize)]
-#[serde(rename_all = "snake_case", tag = "kind")]
-#[non_exhaustive]
-pub enum TransportProfile {
- #[default]
- LocalOnly,
- Nostr {
- profile: NostrProfile,
- },
- Reticulum {
- profile: ReticulumProfile,
- },
- MultiTarget {
- profile: MultiTargetProfile,
- },
-}
-
-impl TransportProfile {
- pub fn local_only() -> Self {
- Self::LocalOnly
- }
-
- pub fn nostr(profile: NostrProfile) -> Self {
- Self::Nostr { profile }
- }
-
- pub fn reticulum(profile: ReticulumProfile) -> Self {
- Self::Reticulum { profile }
- }
-
- pub fn multi_target(profile: MultiTargetProfile) -> Self {
- Self::MultiTarget { profile }
- }
-
- pub(crate) fn transport_profile_id(&self) -> &'static str {
- match self {
- Self::LocalOnly => "local_only",
- Self::Nostr { .. } => "nostr",
- Self::Reticulum { .. } => "reticulum",
- Self::MultiTarget { .. } => "multi_target",
- }
- }
-
- pub(crate) fn target_set(&self) -> Result<Option<TargetSet>, RadrootsSdkError> {
- match self {
- Self::LocalOnly => Ok(None),
- Self::Nostr { profile } => Ok(Some(profile.target_set().clone())),
- Self::Reticulum { profile } => Ok(Some(profile.target_set()?)),
- Self::MultiTarget { profile } => {
- let mut targets = profile.nostr().target_set().targets().to_vec();
- targets.extend(profile.reticulum().target_set()?.into_targets());
- Ok(Some(TargetSet::transport_targets(targets)?))
- }
- }
- }
-
- pub(crate) fn configured_transport_targets(&self) -> Result<Vec<Target>, RadrootsSdkError> {
- Ok(self
- .target_set()?
- .map(TargetSet::into_targets)
- .unwrap_or_default())
- }
-
- pub(crate) fn transport_statuses(&self) -> Vec<RadrootsTransportStatus> {
- match self {
- Self::LocalOnly => vec![
- RadrootsTransportStatus::new(
- TransportId::LOCAL,
- true,
- RadrootsTransportImplementationState::Real,
- false,
- "local persistence only",
- )
- .with_profile_id(self.transport_profile_id()),
- ],
- Self::Nostr { .. } => vec![nostr_transport_status(self.transport_profile_id())],
- Self::Reticulum { profile } => {
- vec![reticulum_transport_status(
- self.transport_profile_id(),
- profile.endpoint_uri(),
- )]
- }
- Self::MultiTarget { profile } => vec![
- nostr_transport_status(self.transport_profile_id()),
- reticulum_transport_status(
- self.transport_profile_id(),
- profile.reticulum().endpoint_uri(),
- ),
- ],
- }
- }
-
- pub(crate) fn configured_nostr_relay_urls(&self) -> Vec<String> {
- match self {
- Self::Nostr { profile } => profile.relay_urls(),
- Self::MultiTarget { profile } => profile.nostr().relay_urls(),
- Self::LocalOnly | Self::Reticulum { .. } => Vec::new(),
- }
- }
-}
-
-fn nostr_transport_status(profile_id: &str) -> RadrootsTransportStatus {
- RadrootsTransportStatus::new(
- TransportId::NOSTR,
- true,
- RadrootsTransportImplementationState::Real,
- true,
- "ready",
- )
- .with_profile_id(profile_id)
-}
-
-fn reticulum_transport_status(profile_id: &str, endpoint_uri: &str) -> RadrootsTransportStatus {
- RadrootsTransportStatus::new(
- TransportId::RETICULUM,
- true,
- RadrootsTransportImplementationState::Real,
- false,
- RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE,
- )
- .with_profile_id(profile_id)
- .with_endpoint_uri(endpoint_uri)
- .with_maturity(RadrootsTransportCapabilityMaturity::Preview)
- .with_availability(RadrootsTransportCapabilityAvailability::Unavailable)
-}
-
-impl From<RadrootsTransportDeliveryReceipt> for TransportReceipt {
- fn from(value: RadrootsTransportDeliveryReceipt) -> Self {
- Self {
- request_id: value.request_id().to_owned(),
- target_set: value.target_set().clone(),
- target_receipts: value.target_receipts().to_vec(),
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
-pub struct TransportReceipt {
- request_id: String,
- target_set: TransportTargetSet,
- target_receipts: Vec<RadrootsTransportTargetReceipt>,
-}
-
-impl TransportReceipt {
- pub fn request_id(&self) -> &str {
- self.request_id.as_str()
- }
-
- pub fn target_set(&self) -> &TransportTargetSet {
- &self.target_set
- }
-
- pub fn target_receipts(&self) -> &[RadrootsTransportTargetReceipt] {
- self.target_receipts.as_slice()
- }
-
- pub fn satisfied_target_count(
- &self,
- satisfaction_class: RadrootsTransportSatisfactionClass,
- ) -> usize {
- self.target_receipts
- .iter()
- .filter(|receipt| receipt.status.counts_as_satisfied(satisfaction_class))
- .count()
- }
-
- pub fn is_satisfied_by(&self, policy: &SatisfactionPolicy) -> Result<bool, RadrootsSdkError> {
- let receipt = RadrootsTransportDeliveryReceipt::new(
- self.request_id.clone(),
- self.target_set.clone(),
- self.target_receipts.clone(),
- )?;
- Ok(receipt.is_satisfied_by(&policy.transport_satisfaction_policy()?)?)
- }
-}
-
-fn normalized_nostr_relay_url(
- value: &str,
- policy: NostrRelayUrlPolicy,
-) -> Result<String, RadrootsSdkError> {
- let relay = RelayUrl::parse(value, policy.nostr_transport_policy())?;
- Ok(relay.into_string())
-}
-
-#[cfg(test)]
-#[path = "../tests/unit/transport_tests.rs"]
-mod tests;
+//! Transport capability composition.
diff --git a/crates/sdk/tests/package_boundary.rs b/crates/sdk/tests/package_boundary.rs
@@ -0,0 +1,72 @@
+use std::collections::BTreeSet;
+
+const MANIFEST: &str = include_str!("../Cargo.toml");
+const ROOT: &str = include_str!("../src/lib.rs");
+
+#[test]
+fn manifest_has_final_identity_and_dependency_boundary() {
+ assert!(MANIFEST.contains("name = \"radroots_sdk\""));
+ assert!(MANIFEST.contains("publish = false"));
+ assert!(MANIFEST.contains("version.workspace = true"));
+ assert!(MANIFEST.contains("name = \"package_boundary\""));
+
+ let dependencies = dependency_names(MANIFEST);
+ let expected = BTreeSet::from([
+ "radroots_core",
+ "radroots_event",
+ "radroots_event_codec",
+ "radroots_geonames",
+ "radroots_identity",
+ "radroots_nostr",
+ "radroots_nostr_connect",
+ "radroots_protocol",
+ "radroots_secrets",
+ "radroots_signing",
+ "radroots_storage",
+ "radroots_storage_sqlite",
+ "radroots_sync",
+ "radroots_trade",
+ "radroots_transport",
+ "radroots_transport_nostr",
+ ]);
+ assert_eq!(dependencies, expected);
+}
+
+#[test]
+fn root_declares_exact_final_module_skeleton() {
+ let actual = ROOT
+ .lines()
+ .filter_map(|line| line.trim().strip_prefix("pub mod "))
+ .map(|module| module.trim_end_matches(';'))
+ .collect::<BTreeSet<_>>();
+ let expected = BTreeSet::from([
+ "capability",
+ "client",
+ "diagnostics",
+ "error",
+ "farm",
+ "listing",
+ "signing",
+ "storage",
+ "sync",
+ "trade",
+ "transport",
+ ]);
+ assert_eq!(actual, expected);
+ assert!(!ROOT.contains("no_std"));
+}
+
+fn dependency_names(manifest: &str) -> BTreeSet<&str> {
+ let dependencies = manifest
+ .split_once("[dependencies]")
+ .expect("dependency section")
+ .1
+ .split_once("[[test]]")
+ .expect("test section")
+ .0;
+ dependencies
+ .lines()
+ .filter_map(|line| line.split_once(" = ").map(|(name, _)| name.trim()))
+ .filter(|name| name.starts_with("radroots_"))
+ .collect()
+}