at protocol indexer with flexible filtering, xrpc queries, and a cursor-backed event stream, built on fjall
at-protocol
atproto
indexer
rust
fjall
1use std::ops::Not;
2
3use jacquard::types::string::Handle;
4use jacquard::IntoStatic;
5use jacquard_common::types::ident::AtIdentifier;
6use jacquard_common::types::string::Did;
7use jacquard_identity::resolver::{IdentityResolver, PlcSource, ResolverOptions};
8use jacquard_identity::JacquardResolver;
9use miette::{IntoDiagnostic, Result};
10use url::Url;
11
12pub struct Resolver {
13 inner: JacquardResolver,
14}
15
16impl Resolver {
17 pub fn new(plc_url: Url) -> Self {
18 let http = reqwest::Client::new();
19 let mut opts = ResolverOptions::default();
20 opts.plc_source = PlcSource::PlcDirectory { base: plc_url };
21
22 let inner = JacquardResolver::new(http, opts);
23
24 Self { inner }
25 }
26
27 pub async fn resolve_did(&self, identifier: &AtIdentifier<'_>) -> Result<Did<'static>> {
28 match identifier {
29 AtIdentifier::Did(did) => Ok(did.clone().into_static()),
30 AtIdentifier::Handle(handle) => {
31 let did = self.inner.resolve_handle(handle).await.into_diagnostic()?;
32 Ok(did.into_static())
33 }
34 }
35 }
36
37 pub async fn resolve_identity_info(&self, did: &Did<'_>) -> Result<(Url, Option<Handle<'_>>)> {
38 let doc_resp = self.inner.resolve_did_doc(did).await.into_diagnostic()?;
39 let doc = doc_resp.parse().into_diagnostic()?;
40
41 let pds = doc
42 .pds_endpoint()
43 .ok_or_else(|| miette::miette!("no PDS service found in DID Doc for {did}"))?;
44
45 let mut handles = doc.handles();
46 let handle = handles.is_empty().not().then(|| handles.remove(0));
47
48 Ok((pds, handle))
49 }
50}