+1
-1
Cargo.lock
+1
-1
Cargo.lock
+5
-3
crates/jacquard/Cargo.toml
+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
+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
+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