···378378 }
379379 DidStep::PlcHttp if s.starts_with("did:plc:") => {
380380 let url = match &self.opts.plc_source {
381381- PlcSource::PlcDirectory { base } => base.join(did.as_str())?,
381381+ PlcSource::PlcDirectory { base } => {
382382+ // this is odd, the join screws up with the plc directory but NOT slingshot
383383+ Url::parse(&format!("{}{}", base, did.as_str())).expect("Invalid URL")
384384+ }
382385 PlcSource::Slingshot { base } => base.join(did.as_str())?,
383386 };
387387+ println!("Fetching DID document from {}", url);
384388 if let Ok((buf, status)) = self.get_json_bytes(url).await {
385389 return Ok(DidDocResponse {
386390 buffer: buf,
+28-7
crates/jacquard-identity/src/resolver.rs
···3636#[allow(missing_docs)]
3737pub enum IdentityError {
3838 #[error("unsupported DID method: {0}")]
3939- #[diagnostic(code(jacquard_identity::unsupported_did_method), help("supported DID methods: did:web, did:plc"))]
3939+ #[diagnostic(
4040+ code(jacquard_identity::unsupported_did_method),
4141+ help("supported DID methods: did:web, did:plc")
4242+ )]
4043 UnsupportedDidMethod(String),
4144 #[error("invalid well-known atproto-did content")]
4242- #[diagnostic(code(jacquard_identity::invalid_well_known), help("expected first non-empty line to be a DID"))]
4545+ #[diagnostic(
4646+ code(jacquard_identity::invalid_well_known),
4747+ help("expected first non-empty line to be a DID")
4848+ )]
4349 InvalidWellKnown,
4450 #[error("missing PDS endpoint in DID document")]
4551 #[diagnostic(code(jacquard_identity::missing_pds_endpoint))]
4652 MissingPdsEndpoint,
4753 #[error("HTTP error: {0}")]
4848- #[diagnostic(code(jacquard_identity::http), help("check network connectivity and TLS configuration"))]
5454+ #[diagnostic(
5555+ code(jacquard_identity::http),
5656+ help("check network connectivity and TLS configuration")
5757+ )]
4958 Http(#[from] TransportError),
5059 #[error("HTTP status {0}")]
5151- #[diagnostic(code(jacquard_identity::http_status), help("verify well-known paths or PDS XRPC endpoints"))]
6060+ #[diagnostic(
6161+ code(jacquard_identity::http_status),
6262+ help("verify well-known paths or PDS XRPC endpoints")
6363+ )]
5264 HttpStatus(StatusCode),
5365 #[error("XRPC error: {0}")]
5454- #[diagnostic(code(jacquard_identity::xrpc), help("enable PDS fallback or public resolver if needed"))]
6666+ #[diagnostic(
6767+ code(jacquard_identity::xrpc),
6868+ help("enable PDS fallback or public resolver if needed")
6969+ )]
5570 Xrpc(String),
5671 #[error("URL parse error: {0}")]
5772 #[diagnostic(code(jacquard_identity::url))]
···6479 #[diagnostic(code(jacquard_identity::serde))]
6580 Serde(#[from] serde_json::Error),
6681 #[error("invalid DID document: {0}")]
6767- #[diagnostic(code(jacquard_identity::invalid_doc), help("validate keys and services; ensure AtprotoPersonalDataServer service exists"))]
8282+ #[diagnostic(
8383+ code(jacquard_identity::invalid_doc),
8484+ help("validate keys and services; ensure AtprotoPersonalDataServer service exists")
8585+ )]
6886 InvalidDoc(String),
6987 #[error(transparent)]
7088 #[diagnostic(code(jacquard_identity::data))]
7189 Data(#[from] AtDataError),
7290 /// DID document id did not match requested DID; includes the fetched document
7391 #[error("DID doc id mismatch")]
7474- #[diagnostic(code(jacquard_identity::doc_id_mismatch), help("document id differs from requested DID; do not trust this document"))]
9292+ #[diagnostic(
9393+ code(jacquard_identity::doc_id_mismatch),
9494+ help("document id differs from requested DID; do not trust this document")
9595+ )]
7596 DocIdMismatch {
7697 expected: Did<'static>,
7798 doc: DidDocument<'static>,
+6-13
crates/jacquard/src/client/credential_session.rs
···403403 // Under Tokio, use `block_in_place` to make a blocking RwLock read safe.
404404 if tokio::runtime::Handle::try_current().is_ok() {
405405 tokio::task::block_in_place(|| {
406406- self.endpoint
407407- .blocking_read()
408408- .clone()
409409- .unwrap_or(
410410- Url::parse("https://public.bsky.app")
411411- .expect("public appview should be valid url"),
412412- )
413413- })
414414- } else {
415415- self.endpoint
416416- .blocking_read()
417417- .clone()
418418- .unwrap_or(
406406+ self.endpoint.blocking_read().clone().unwrap_or(
419407 Url::parse("https://public.bsky.app")
420408 .expect("public appview should be valid url"),
421409 )
410410+ })
411411+ } else {
412412+ self.endpoint.blocking_read().clone().unwrap_or(
413413+ Url::parse("https://public.bsky.app").expect("public appview should be valid url"),
414414+ )
422415 }
423416 }
424417 async fn send<R: jacquard_common::types::xrpc::XrpcRequest + Send>(
+10-5
crates/jacquard/src/main.rs
···11-use std::sync::Arc;
21use clap::Parser;
32use jacquard::CowStr;
43use jacquard::api::app_bsky::feed::get_timeline::GetTimeline;
54use jacquard::client::credential_session::{CredentialSession, SessionKey};
65use jacquard::client::{AtpSession, MemorySessionStore};
77-use jacquard::identity::PublicResolver as JacquardResolver;
86use jacquard::types::xrpc::XrpcClient;
77+use jacquard_identity::slingshot_resolver_default;
98use miette::IntoDiagnostic;
99+use std::sync::Arc;
10101111#[derive(Parser, Debug)]
1212#[command(author, version, about = "Jacquard - AT Protocol client demo")]
···2424 let args = Args::parse();
25252626 // Resolver + in-memory store
2727- let resolver = Arc::new(JacquardResolver::default());
2727+ let resolver = Arc::new(slingshot_resolver_default());
2828 let store: Arc<MemorySessionStore<SessionKey, AtpSession>> = Arc::new(Default::default());
2929 let client = Arc::new(resolver.clone());
3030 let session = CredentialSession::new(store, client);
31313232- // Login; resolves PDS from handle/DID automatically. Persisted under (did, "session").
3332 let _ = session
3434- .login(args.username.clone(), args.password.clone(), None, None, None)
3333+ .login(
3434+ args.username.clone(),
3535+ args.password.clone(),
3636+ None,
3737+ None,
3838+ None,
3939+ )
3540 .await
3641 .into_diagnostic()?;
3742