app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 3f2d24e1274a4dfc17c433ea1f8e6dd4afaef892
parent f981d6905a74e20414a5102f82c392cffa49a5d8
Author: triesap <tyson@radroots.org>
Date:   Sat, 18 Jul 2026 11:38:18 +0000

build: bind Studio to alpha event contract

- exact-pin direct Radroots dependencies to the 1.0.0-alpha.1 contract
- replace the missing mounted MF2 dependency with an exact public revision
- migrate NIP-46 client access and make absent client metadata explicit
- restore warning-clean i18n, runtime, and state contract verification

Diffstat:
MCargo.lock | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
MCargo.toml | 30+++++++++++++++---------------
Mcrates/i18n/src/lib.rs | 5+++++
Mcrates/runtime/src/sdk.rs | 8++++----
Mcrates/signer/src/protocol.rs | 15++++++++++-----
Mcrates/state/src/lib.rs | 20++++++++++----------
Mi18n/mf2_i18n.toml | 4+++-
7 files changed, 104 insertions(+), 60 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3403,6 +3403,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] name = "jobserver" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3777,6 +3783,12 @@ dependencies = [ ] [[package]] +name = "mediatype" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120fa187be19d9962f0926633453784691731018a2bf936ddb4e29101b79c4a7" + +[[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3818,6 +3830,7 @@ dependencies = [ [[package]] name = "mf2_i18n" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" dependencies = [ "mf2_i18n_build", "mf2_i18n_core", @@ -3830,6 +3843,7 @@ dependencies = [ [[package]] name = "mf2_i18n_build" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" dependencies = [ "blake3", "hex", @@ -3844,10 +3858,12 @@ dependencies = [ [[package]] name = "mf2_i18n_core" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" [[package]] name = "mf2_i18n_embedded" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" dependencies = [ "mf2_i18n_core", ] @@ -3855,6 +3871,7 @@ dependencies = [ [[package]] name = "mf2_i18n_native" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" dependencies = [ "mf2_i18n_core", "mf2_i18n_embedded", @@ -3866,6 +3883,7 @@ dependencies = [ [[package]] name = "mf2_i18n_runtime" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" dependencies = [ "ed25519-dalek", "hex", @@ -3880,6 +3898,7 @@ dependencies = [ [[package]] name = "mf2_i18n_std" version = "0.1.0" +source = "git+https://github.com/triesap/mf2_i18n.git?rev=e95f0fe090764dc62f5f67f4ff9e207d7e1cd901#e95f0fe090764dc62f5f67f4ff9e207d7e1cd901" dependencies = [ "chrono", "intl_pluralrules", @@ -5092,15 +5111,25 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "radroots_authority" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "radroots_event", "radroots_nostr", ] [[package]] +name = "radroots_blossom" +version = "1.0.0-alpha.1" +dependencies = [ + "mediatype", + "serde", + "sha2", + "url", +] + +[[package]] name = "radroots_core" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "rust_decimal", "rust_decimal_macros", @@ -5109,19 +5138,22 @@ dependencies = [ [[package]] name = "radroots_event" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "hex", + "jiff-tzdb", + "radroots_blossom", "radroots_core", "secp256k1", "serde", "serde_json", "sha2", + "url", ] [[package]] name = "radroots_event_codec" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "nostr", "radroots_core", @@ -5132,7 +5164,7 @@ dependencies = [ [[package]] name = "radroots_event_store" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "hex", "radroots_event", @@ -5147,7 +5179,7 @@ dependencies = [ [[package]] name = "radroots_geocoder" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "futures-executor", "hex", @@ -5163,10 +5195,9 @@ dependencies = [ [[package]] name = "radroots_identity" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "nostr", - "radroots_event", "radroots_protected_store", "radroots_runtime", "radroots_runtime_paths", @@ -5179,9 +5210,10 @@ dependencies = [ [[package]] name = "radroots_log" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "chrono", + "serde_json", "thiserror 1.0.69", "tracing", "tracing-appender", @@ -5190,7 +5222,7 @@ dependencies = [ [[package]] name = "radroots_nostr" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "nostr", "nostr-sdk", @@ -5204,7 +5236,7 @@ dependencies = [ [[package]] name = "radroots_nostr_accounts" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "radroots_identity", "radroots_nostr_signer", @@ -5219,7 +5251,7 @@ dependencies = [ [[package]] name = "radroots_nostr_connect" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "nostr", "serde", @@ -5230,7 +5262,7 @@ dependencies = [ [[package]] name = "radroots_nostr_signer" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "hex", "nostr", @@ -5248,7 +5280,7 @@ dependencies = [ [[package]] name = "radroots_outbox" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "hex", "radroots_event", @@ -5263,7 +5295,7 @@ dependencies = [ [[package]] name = "radroots_protected_store" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "chacha20poly1305", "getrandom 0.2.17", @@ -5275,14 +5307,14 @@ dependencies = [ [[package]] name = "radroots_protocol_contract_v1" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "serde", ] [[package]] name = "radroots_runtime" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "anyhow", "chacha20poly1305", @@ -5312,7 +5344,7 @@ dependencies = [ [[package]] name = "radroots_runtime_paths" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "serde", "thiserror 1.0.69", @@ -5320,7 +5352,7 @@ dependencies = [ [[package]] name = "radroots_runtime_store" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "radroots_sql_core", "serde", @@ -5363,11 +5395,11 @@ dependencies = [ [[package]] name = "radroots_secret_vault" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" [[package]] name = "radroots_sql_core" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "chrono", "futures-executor", @@ -5536,7 +5568,7 @@ dependencies = [ [[package]] name = "radroots_trade" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "base64 0.22.1", "hex", @@ -5554,7 +5586,7 @@ dependencies = [ [[package]] name = "radroots_transport" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "serde", "sha2", @@ -5562,7 +5594,7 @@ dependencies = [ [[package]] name = "radroots_transport_nostr" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "futures", "nostr", @@ -5580,7 +5612,7 @@ dependencies = [ [[package]] name = "radroots_transport_reticulum" -version = "0.1.0-alpha.2" +version = "1.0.0-alpha.1" dependencies = [ "radroots_transport", ] diff --git a/Cargo.toml b/Cargo.toml @@ -31,22 +31,22 @@ futures-util = "0.3" gpui = "0.2.2" gpui-component = "0.5.1" gpui-component-assets = "0.5.1" -mf2_i18n = { path = "../../../vendor/triesap/mf2_i18n/crates/mf2_i18n" } -radroots_core = { path = "../lib/crates/core", default-features = false, features = ["std"] } -radroots_authority = { path = "../lib/crates/authority" } -radroots_event = { path = "../lib/crates/event", default-features = false, features = ["serde", "std"] } -radroots_event_codec = { path = "../lib/crates/event_codec", features = ["serde_json"] } -radroots_identity = { path = "../lib/crates/identity" } -radroots_runtime_store = { path = "../lib/crates/runtime_store", features = ["native"] } -radroots_nostr = { path = "../lib/crates/nostr", features = ["client"] } -radroots_nostr_accounts = { path = "../lib/crates/nostr_accounts" } -radroots_nostr_connect = { path = "../lib/crates/nostr_connect" } -radroots_protected_store = { path = "../lib/crates/protected_store" } -radroots_runtime_paths = { path = "../lib/crates/runtime_paths" } -radroots_secret_vault = { path = "../lib/crates/secret_vault", default-features = false, features = ["std"] } +mf2_i18n = { version = "=0.1.0", git = "https://github.com/triesap/mf2_i18n.git", rev = "e95f0fe090764dc62f5f67f4ff9e207d7e1cd901", default-features = false } +radroots_core = { version = "=1.0.0-alpha.1", path = "../lib/crates/core", default-features = false, features = ["std"] } +radroots_authority = { version = "=1.0.0-alpha.1", path = "../lib/crates/authority" } +radroots_event = { version = "=1.0.0-alpha.1", path = "../lib/crates/event", default-features = false, features = ["serde", "std"] } +radroots_event_codec = { version = "=1.0.0-alpha.1", path = "../lib/crates/event_codec", features = ["serde_json"] } +radroots_identity = { version = "=1.0.0-alpha.1", path = "../lib/crates/identity" } +radroots_runtime_store = { version = "=1.0.0-alpha.1", path = "../lib/crates/runtime_store", features = ["native"] } +radroots_nostr = { version = "=1.0.0-alpha.1", path = "../lib/crates/nostr", features = ["client"] } +radroots_nostr_accounts = { version = "=1.0.0-alpha.1", path = "../lib/crates/nostr_accounts" } +radroots_nostr_connect = { version = "=1.0.0-alpha.1", path = "../lib/crates/nostr_connect" } +radroots_protected_store = { version = "=1.0.0-alpha.1", path = "../lib/crates/protected_store" } +radroots_runtime_paths = { version = "=1.0.0-alpha.1", path = "../lib/crates/runtime_paths" } +radroots_secret_vault = { version = "=1.0.0-alpha.1", path = "../lib/crates/secret_vault", default-features = false, features = ["std"] } radroots_sdk = { path = "../sdk/crates/sdk", features = ["local-runtime"] } -radroots_sql_core = { path = "../lib/crates/sql_core", features = ["native"] } -radroots_trade = { path = "../lib/crates/trade", default-features = false, features = ["std", "serde", "serde_json"] } +radroots_sql_core = { version = "=1.0.0-alpha.1", path = "../lib/crates/sql_core", features = ["native"] } +radroots_trade = { version = "=1.0.0-alpha.1", path = "../lib/crates/trade", default-features = false, features = ["std", "serde", "serde_json"] } radroots_studio_app_core = { path = "crates/runtime", version = "0.1.0" } radroots_studio_app_i18n = { path = "crates/i18n", version = "0.1.0" } radroots_studio_app_types = { path = "crates/types", version = "0.1.0" } diff --git a/crates/i18n/src/lib.rs b/crates/i18n/src/lib.rs @@ -123,11 +123,16 @@ mod tests { .iter() .copied() .collect::<BTreeSet<_>>(); + let generated_variant_keys = super::DEFAULT_CATALOG_KEY_VARIANTS + .iter() + .map(|(key, _variant)| *key) + .collect::<BTreeSet<_>>(); let typed_keys = AppTextKey::ALL .iter() .map(|key| key.id()) .collect::<BTreeSet<_>>(); + assert_eq!(generated_variant_keys, catalog_keys); assert_eq!(typed_keys, catalog_keys); } diff --git a/crates/runtime/src/sdk.rs b/crates/runtime/src/sdk.rs @@ -2367,8 +2367,8 @@ mod tests { let issue = status .last_issue .expect("degraded status should include issue"); - assert_eq!(issue.code, "invalid_relay_url"); - assert_eq!(issue.class, "configuration"); + assert_eq!(issue.code.as_ref(), "invalid_relay_url"); + assert_eq!(issue.class.as_ref(), "configuration"); assert!(!issue.retryable); assert!( issue @@ -2390,7 +2390,7 @@ mod tests { .as_ref() .and_then(|effect| effect.issue.as_ref()) .expect("failed diagnostics effect should include issue"); - assert_eq!(issue.code, "invalid_relay_url"); + assert_eq!(issue.code.as_ref(), "invalid_relay_url"); assert!(runtime.request_shutdown()); let _ = fs::remove_dir_all(storage_root); } @@ -2532,7 +2532,7 @@ mod tests { .as_ref() .and_then(|effect| effect.issue.as_ref()) .expect("blocked refresh should expose lifecycle issue"); - assert_eq!(issue.code, "sdk_lifecycle_busy"); + assert_eq!(issue.code.as_ref(), "sdk_lifecycle_busy"); assert_eq!(issue.detail_json["state"], "RebuildingProjections"); let complete = runtime diff --git a/crates/signer/src/protocol.rs b/crates/signer/src/protocol.rs @@ -227,6 +227,7 @@ fn connect_request_for_target( .expect("signer public key is derived from a validated identity"), secret: target.connect_secret.clone(), requested_permissions: target.requested_permissions.clone(), + client_metadata: None, } } @@ -355,7 +356,7 @@ impl ConnectedRemoteSignerSessionClient { vec![client_identity.public_key_hex()], ) .map_err(|error| RadrootsAppRemoteSignerError::ConnectFailed(error.to_string()))?; - let notifications = client.notifications(); + let notifications = client.clone().into_inner().notifications(); client .subscribe(filter, None) .await @@ -784,11 +785,15 @@ mod tests { match request { RadrootsNostrConnectRequest::Connect { requested_permissions, + client_metadata, .. - } => assert_eq!( - requested_permissions.to_string(), - "sign_event:kind:1,switch_relays" - ), + } => { + assert_eq!( + requested_permissions.to_string(), + "sign_event:kind:1,switch_relays" + ); + assert!(client_metadata.is_none()); + } other => panic!("unexpected request: {other:?}"), } } diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs @@ -3488,7 +3488,7 @@ mod tests { ); assert_eq!( store.projection().products.editor, - ProductEditorState::Open(super::ProductEditorSession { + ProductEditorState::Open(Box::new(super::ProductEditorSession { selected_product_id: None, draft: ProductEditorDraft::default(), publish_blockers: vec![ @@ -3499,7 +3499,7 @@ mod tests { ProductPublishBlocker::SetStock, ProductPublishBlocker::AttachAvailability, ], - }) + })) ); assert_eq!( @@ -3510,11 +3510,11 @@ mod tests { ); assert_eq!( store.projection().products.editor, - ProductEditorState::Open(super::ProductEditorSession { + ProductEditorState::Open(Box::new(super::ProductEditorSession { selected_product_id: None, draft: ready_draft.clone(), publish_blockers: vec![ProductPublishBlocker::AttachAvailability], - }) + })) ); assert_eq!( @@ -3526,11 +3526,11 @@ mod tests { ); assert_eq!( store.projection().products.editor, - ProductEditorState::Open(super::ProductEditorSession { + ProductEditorState::Open(Box::new(super::ProductEditorSession { selected_product_id: Some(product_id), draft: ready_draft, publish_blockers: vec![ProductPublishBlocker::AttachAvailability], - }) + })) ); assert_eq!( @@ -3631,7 +3631,7 @@ mod tests { ); assert_eq!( store.projection().products.editor, - ProductEditorState::Open(super::ProductEditorSession { + ProductEditorState::Open(Box::new(super::ProductEditorSession { selected_product_id: Some(product_id), draft: ProductEditorDraft { title: "Salad mix".to_owned(), @@ -3645,7 +3645,7 @@ mod tests { status: radroots_studio_app_view::ProductStatus::Published, }, publish_blockers: Vec::new(), - }) + })) ); assert_eq!( @@ -3656,11 +3656,11 @@ mod tests { ); assert_eq!( store.projection().products.editor, - ProductEditorState::Open(super::ProductEditorSession { + ProductEditorState::Open(Box::new(super::ProductEditorSession { selected_product_id: Some(product_id), draft: stale_draft, publish_blockers: vec![ProductPublishBlocker::AttachAvailability], - }) + })) ); } diff --git a/i18n/mf2_i18n.toml b/i18n/mf2_i18n.toml @@ -1,7 +1,9 @@ version = 1 default_locale = "en" +locales = ["en"] project_salt_path = "id_salt.txt" [[sources]] -path = "locales" +name = "studio" layout = "locale-namespace" +root = "locales"