A better Rust ATProto crate

tested one commit too late

Orual 05de6ab5 a867fc82

Changed files
+56 -10
crates
jacquard
+1 -1
Cargo.lock
··· 1353 1353 1354 1354 [[package]] 1355 1355 name = "jacquard" 1356 - version = "0.2.0" 1356 + version = "0.2.1" 1357 1357 dependencies = [ 1358 1358 "async-trait", 1359 1359 "bon",
+5 -3
crates/jacquard/Cargo.toml
··· 2 2 name = "jacquard" 3 3 description.workspace = true 4 4 edition.workspace = true 5 - version.workspace = true 5 + version = "0.2.1" 6 6 authors.workspace = true 7 7 repository.workspace = true 8 8 keywords.workspace = true ··· 12 12 license.workspace = true 13 13 14 14 [features] 15 - default = ["api_all", "dns"] 15 + default = ["api_all", "dns", "fancy"] 16 16 derive = ["dep:jacquard-derive"] 17 17 api = ["jacquard-api/com_atproto"] 18 18 api_all = ["api", "jacquard-api/app_bsky", "jacquard-api/chat_bsky", "jacquard-api/tools_ozone"] 19 19 dns = ["dep:hickory-resolver"] 20 + fancy = ["miette/fancy"] 20 21 21 22 [lib] 22 23 name = "jacquard" ··· 25 26 [[bin]] 26 27 name = "jacquard" 27 28 path = "src/main.rs" 29 + 28 30 29 31 [dependencies] 30 32 bon = "3" ··· 35 37 jacquard-api = { version = "0.2.0", path = "../jacquard-api" } 36 38 jacquard-common = { version = "0.2.0", path = "../jacquard-common" } 37 39 jacquard-derive = { version = "0.2.0", path = "../jacquard-derive", optional = true } 38 - miette.workspace = true 40 + miette = { workspace = true } 39 41 reqwest = { workspace = true, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] } 40 42 serde.workspace = true 41 43 serde_html_form.workspace = true
+49 -5
crates/jacquard/src/identity/resolver.rs
··· 9 9 //! Parsing returns a `DidDocResponse` so callers can borrow from the response buffer 10 10 //! and optionally validate the document `id` against the requested DID. 11 11 12 + use std::collections::BTreeMap; 13 + use std::str::FromStr; 14 + 12 15 // use crate::CowStr; // not currently needed directly here 13 16 use crate::client::XrpcExt; 14 17 use bon::Builder; 15 18 use bytes::Bytes; 16 - use jacquard_common::IntoStatic; 19 + use jacquard_common::types::did_doc::Service; 20 + use jacquard_common::types::string::AtprotoStr; 21 + use jacquard_common::types::uri::Uri; 22 + use jacquard_common::types::value::Data; 23 + use jacquard_common::{CowStr, IntoStatic}; 17 24 use miette::Diagnostic; 18 25 use percent_encoding::percent_decode_str; 19 26 use reqwest::StatusCode; ··· 124 131 /// Parse as borrowed DidDocument<'_> 125 132 pub fn parse<'b>(&'b self) -> Result<DidDocument<'b>, IdentityError> { 126 133 if self.status.is_success() { 127 - serde_json::from_slice::<DidDocument<'b>>(&self.buffer).map_err(IdentityError::from) 134 + if let Ok(doc) = serde_json::from_slice::<DidDocument<'b>>(&self.buffer) { 135 + Ok(doc) 136 + } else if let Ok(mini_doc) = serde_json::from_slice::<MiniDoc<'b>>(&self.buffer) { 137 + Ok(DidDocument { 138 + id: mini_doc.did, 139 + also_known_as: Some(vec![CowStr::from(mini_doc.handle)]), 140 + verification_method: None, 141 + service: Some(vec![Service { 142 + id: CowStr::new_static("#atproto_pds"), 143 + r#type: CowStr::new_static("AtprotoPersonalDataServer"), 144 + service_endpoint: Some(Data::String(AtprotoStr::Uri(Uri::Https( 145 + Url::from_str(&mini_doc.pds).unwrap(), 146 + )))), 147 + extra_data: BTreeMap::new(), 148 + }]), 149 + extra_data: BTreeMap::new(), 150 + }) 151 + } else { 152 + Err(IdentityError::MissingPdsEndpoint) 153 + } 128 154 } else { 129 155 Err(IdentityError::HttpStatus(self.status)) 130 156 } ··· 149 175 /// Parse as owned DidDocument<'static> 150 176 pub fn into_owned(self) -> Result<DidDocument<'static>, IdentityError> { 151 177 if self.status.is_success() { 152 - serde_json::from_slice::<DidDocument<'_>>(&self.buffer) 153 - .map(|d| d.into_static()) 154 - .map_err(IdentityError::from) 178 + if let Ok(doc) = serde_json::from_slice::<DidDocument<'_>>(&self.buffer) { 179 + Ok(doc.into_static()) 180 + } else if let Ok(mini_doc) = serde_json::from_slice::<MiniDoc<'_>>(&self.buffer) { 181 + Ok(DidDocument { 182 + id: mini_doc.did, 183 + also_known_as: Some(vec![CowStr::from(mini_doc.handle)]), 184 + verification_method: None, 185 + service: Some(vec![Service { 186 + id: CowStr::new_static("#atproto_pds"), 187 + r#type: CowStr::new_static("AtprotoPersonalDataServer"), 188 + service_endpoint: Some(Data::String(AtprotoStr::Uri(Uri::Https( 189 + Url::from_str(&mini_doc.pds).unwrap(), 190 + )))), 191 + extra_data: BTreeMap::new(), 192 + }]), 193 + extra_data: BTreeMap::new(), 194 + } 195 + .into_static()) 196 + } else { 197 + Err(IdentityError::MissingPdsEndpoint) 198 + } 155 199 } else { 156 200 Err(IdentityError::HttpStatus(self.status)) 157 201 }
+1 -1
crates/jacquard/src/main.rs
··· 3 3 use jacquard::api::app_bsky::feed::get_timeline::GetTimeline; 4 4 use jacquard::api::com_atproto::server::create_session::CreateSession; 5 5 use jacquard::client::{BasicClient, Session}; 6 - use jacquard::identity::resolver::{slingshot_resolver_default, IdentityResolver}; 6 + use jacquard::identity::resolver::{IdentityResolver, slingshot_resolver_default}; 7 7 use jacquard::types::string::Handle; 8 8 use miette::IntoDiagnostic; 9 9