···74747575#[cfg(test)]7676mod tests {7777- use std::borrow::Cow;7878-7977 use atproto::{Did, tid::Tid};8078 use auth::jwt::Claims;8179···260262261263 // Generate the body of the 'sh.tangled.repo.create' request.262264 let create = lexicon::sh_tangled::repo::create::Input {263263- rkey: Cow::Borrowed(&rkey),265265+ rkey: rkey.to_string(),264266 default_branch: Some("main".into()),265267 source: None,266268 };
···345345 ));346346 };347347348348- let repo_did = coll.repo.did().unwrap();349349- let repo_rkey = coll.repo.rkey.unwrap();348348+ let repo_did = coll.repo.authority();349349+ let repo_rkey = coll.repo.rkey();350350+ if coll.repo.collection() != "sh.tangled.repo" {351351+ return Err(anyhow::anyhow!(352352+ "repo parameter in should refer to a 'sh.tangled.repo'"353353+ ));354354+ }350355351356 let policy = AddCollaboratorPolicy;352357 let repository = RepositoryRef::new(repo_did, repo_rkey);
+13-25
crates/knot/src/services/seed.rs
···11use atproto::{Did, tid::Tid};22-use lexicon::sh_tangled::{knot::Member, repo::Repo};22+use lexicon::{33+ com::atproto::repo::list_records::Record,44+ sh_tangled::{knot::Member, repo::Repo},55+};3647use crate::{model::Knot, services::atrepo, types::RecordKey};58···2017 {2118 let knot = knot.clone();2219 async move |records| {2323- for record in records {2424- let rkey = record2525- .uri2626- .rkey2727- .ok_or(anyhow::anyhow!("record uri missing rkey"))?;2828-2929- let Ok(member) = serde_json::from_str::<Member>(record.value.get()) else {2020+ for Record { uri, cid, value } in records {2121+ let Ok(member) = serde_json::from_str::<Member>(value.get()) else {3022 continue;3123 };32243333- knot.add_member(rkey, &rev, &record.cid, &member).await?;2525+ knot.add_member(uri.rkey(), &rev, &cid, &member).await?;3426 }3527 Ok(())3628 }···4850 {4951 let knot = knot.clone();5052 async move |records| {5151- for record in records {5252- let rkey = record5353- .uri5454- .rkey5555- .ok_or(anyhow::anyhow!("record uri missing rkey"))?;5656-5757- let Ok(public_key) = serde_json::from_str(record.value.get()) else {5353+ for Record { uri, cid, value } in records {5454+ let Ok(public_key) = serde_json::from_str(value.get()) else {5855 continue;5956 };60576158 knot.database()6262- .upsert_public_key(&did, rkey, &rev, &record.cid, &public_key)5959+ .upsert_public_key(&did, uri.rkey(), &rev, &cid, &public_key)6360 .await?;64616565- tracing::info!(?did, ?rkey, "new public key");6262+ tracing::info!(?did, ?uri, "new public key");6663 }67646865 Ok(())···8188 let knot = knot.clone();8289 async move |records| {8390 for record in records {8484- let rkey = record8585- .uri8686- .rkey8787- .ok_or(anyhow::anyhow!("record uri missing rkey"))?;8888-8991 let Ok(repo) = serde_json::from_str::<Repo>(record.value.get()) else {9090- tracing::error!(?record, "error parsing record");9292+ tracing::error!(value = ?record.value, "error parsing record value");9193 continue;9294 };9395···96108 continue;97109 }981109999- tracing::info!(?did, ?rkey, name = %repo.name, "new repository");111111+ tracing::info!(?did, uri= ?record.uri, name = %repo.name, "new repository");100112 }101113102114 Ok(())
+8-12
crates/knot/src/types.rs
···11use core::fmt;2233-use atproto::Did;33+use atproto::{Did, RecordUri};44use lexicon::com::atproto::repo::list_records::Record;5566pub mod push_certificate;···34343535impl core::error::Error for FromRecordError {}36363737-impl<'a> TryFrom<&'a Record<'a>> for RecordKey<'a> {3737+impl<'a> TryFrom<&'a Record> for RecordKey<'a> {3838 type Error = FromRecordError;3939- fn try_from(value: &'a Record<'a>) -> Result<Self, Self::Error> {4040- let did = value4141- .uri4242- .did()4343- .ok_or("'uri' does not have a did authority")?;4444- let collection = value4545- .uri4646- .collection_str()4747- .ok_or("'uri' does not declare a collection")?;4848- let rkey = value.uri.rkey.ok_or("'uri' does not declare an rkey")?;3939+ fn try_from(value: &'a Record) -> Result<Self, Self::Error> {4040+ let RecordUri {4141+ authority: did,4242+ collection,4343+ rkey,4444+ } = &value.uri;49455046 Ok(Self {5147 did,
+15-22
crates/lexicon/src/com/atproto/repo.rs
···55 //!66 //! <https://docs.bsky.app/docs/api/com-atproto-repo-list-records>77 //!88- use atproto::aturi::AtUri;99- use serde::{Deserialize, Serialize};1010- use serde_json::value::RawValue;1111- use std::borrow::Cow;88+ use atproto::RecordUri;1291313- #[derive(Debug, Deserialize, Serialize)]1414- pub struct Input<'a> {1010+ #[derive(Debug, serde::Deserialize, serde::Serialize)]1111+ pub struct Input {1512 /// The handle or DID of the repo.1616- #[serde(borrow)]1717- pub repo: Cow<'a, str>,1313+ pub repo: String,18141915 /// The NSID of the record type.2020- #[serde(borrow)]2121- pub collection: Cow<'a, str>,1616+ pub collection: String,22172318 /// The number of records to return.2419 ///···2126 #[serde(skip_serializing_if = "Option::is_none")]2227 pub limit: Option<usize>,23282424- #[serde(borrow, skip_serializing_if = "Option::is_none")]2525- pub cursor: Option<Cow<'a, str>>,2929+ #[serde(skip_serializing_if = "Option::is_none")]3030+ pub cursor: Option<String>,26312732 /// Flag to reverse the order of the returned records.2833 #[serde(default)]2934 pub reverse: bool,3035 }31363232- #[derive(Debug, Deserialize, Serialize)]3333- pub struct Output<'a> {3434- #[serde(borrow)]3535- pub cursor: Option<&'a str>,3737+ #[derive(Debug, serde::Deserialize, serde::Serialize)]3838+ pub struct Output {3939+ pub cursor: Option<String>,36403737- pub records: Vec<Record<'a>>,4141+ pub records: Vec<Record>,3842 }39434040- #[derive(Debug, Deserialize, Serialize)]4141- pub struct Record<'a> {4242- #[serde(borrow)]4343- pub uri: AtUri<'a>,4444+ #[derive(Debug, serde::Deserialize, serde::Serialize)]4545+ pub struct Record {4646+ pub uri: RecordUri,44474548 pub cid: String,46494747- pub value: &'a RawValue,5050+ pub value: Box<serde_json::value::RawValue>,4851 }4952}
+2-2
crates/lexicon/src/extra/objectid.rs
···1111///1212/// This only exists because knotserver uses both representations.1313///1414-#[derive(Clone, PartialEq, Eq)]1414+#[derive(Clone, Hash, PartialEq, Eq)]1515pub struct ObjectId<E = Hex> {1616 inner: gix_hash::ObjectId,1717 enc: PhantomData<E>,1818}19192020impl<E> ObjectId<E> {2121- #[must_use] 2121+ #[must_use]2222 pub const fn id(&self) -> gix_hash::ObjectId {2323 self.inner2424 }
···1919#[derive(Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]2020#[serde(rename_all = "camelCase")]2121pub struct Member<'a> {2222- #[serde(borrow)]2323- pub subject: &'a Did,2222+ #[serde(borrow, with = "atproto::serde::cow_did")]2323+ pub subject: Cow<'a, Did>,24242525- /// Spindle instance that the subject is not a member of.2525+ /// Spindle instance that the subject is now a member of.2626 pub instance: Cow<'a, str>,27272828 #[serde(with = "time::serde::rfc3339")]