+8
-2
crates/jacquard-common/src/types/language.rs
+8
-2
crates/jacquard-common/src/types/language.rs
···
1
+
use langtag::InvalidLangTag;
1
2
use serde::{Deserialize, Deserializer, Serialize, de::Error};
2
3
use smol_str::{SmolStr, ToSmolStr};
3
4
use std::fmt;
···
36
37
Ok(Language(SmolStr::new_static(tag.as_str())))
37
38
}
38
39
40
+
fn new_owned(lang: SmolStr) -> Result<Self, SmolStr> {
41
+
let tag = langtag::LangTag::new(&lang).map_err(|e| e.to_smolstr())?;
42
+
Ok(Language(SmolStr::new(tag.as_str())))
43
+
}
44
+
39
45
/// Infallible constructor for when you *know* the string is a valid IETF language tag.
40
46
/// Will panic on invalid tag. If you're manually decoding atproto records
41
47
/// or API values you know are valid (rather than using serde), this is the one to use.
···
75
81
where
76
82
D: Deserializer<'de>,
77
83
{
78
-
let value: &str = Deserialize::deserialize(deserializer)?;
79
-
Self::new(value).map_err(D::Error::custom)
84
+
let value = Deserialize::deserialize(deserializer)?;
85
+
Self::new_owned(value).map_err(D::Error::custom)
80
86
}
81
87
}
82
88
+2
-1
crates/jacquard/src/client.rs
+2
-1
crates/jacquard/src/client.rs
···
452
452
identifier: CowStr<'_>,
453
453
password: CowStr<'_>,
454
454
session_id: Option<CowStr<'_>>,
455
+
pds: Option<Url>,
455
456
) -> ClientResult<(Self, AtpSession)> {
456
457
let session = MemoryCredentialSession::unauthenticated();
457
458
let auth = session
458
-
.login(identifier, password, session_id, None, None)
459
+
.login(identifier, password, session_id, None, None, pds)
459
460
.await?;
460
461
Ok((session, auth))
461
462
}
+10
-1
crates/jacquard/src/client/credential_session.rs
+10
-1
crates/jacquard/src/client/credential_session.rs
···
204
204
session_id: Option<CowStr<'_>>,
205
205
allow_takendown: Option<bool>,
206
206
auth_factor_token: Option<CowStr<'_>>,
207
+
pds: Option<Url>,
207
208
) -> std::result::Result<AtpSession, ClientError>
208
209
where
209
210
S: Any + 'static,
···
213
214
tracing::info_span!("credential_session_login", identifier = %identifier).entered();
214
215
215
216
// Resolve PDS base
216
-
let pds = if identifier.as_ref().starts_with("http://")
217
+
let pds = if let Some(pds) = pds {
218
+
pds
219
+
} else if identifier.as_ref().starts_with("http://")
217
220
|| identifier.as_ref().starts_with("https://")
218
221
{
219
222
Url::parse(identifier.as_ref()).map_err(|e: url::ParseError| {
···
231
234
resp.into_owned()?.pds_endpoint().ok_or_else(|| {
232
235
ClientError::invalid_request("missing PDS endpoint")
233
236
.with_help("DID document must include a PDS service endpoint")
237
+
})?
238
+
} else if identifier.as_ref().contains("@") && !identifier.as_ref().starts_with("@") {
239
+
// we're going to assume its an email
240
+
pds.ok_or_else(|| {
241
+
ClientError::invalid_request("missing PDS endpoint")
242
+
.with_help("When logging in with email, we need your PDS")
234
243
})?
235
244
} else {
236
245
// treat as handle