use jacquard_common::types::{cid::Cid, string::Did, tid::Tid}; use crate::types::RepoStatus; use super::*; #[derive(Deserialize)] pub struct GetLatestCommit { pub did: Did, } #[derive(Serialize)] pub struct GetLatestCommitOutput { pub cid: Cid, pub rev: Tid, } pub async fn handle( State(hydrant): State, ExtractXrpc(req): ExtractXrpc, ) -> XrpcResult> { let Some(state) = hydrant .repos .get(&req.did) .state() .await .map_err(internal_error)? else { return Err(xrpc_error(StatusCode::NOT_FOUND, "RepoNotFound", None)); }; // return specific errors for inactive account states let xrpc_err = match &state.status { RepoStatus::Takendown => Some(("RepoTakendown", None)), RepoStatus::Suspended => Some(("RepoSuspended", None)), RepoStatus::Deactivated => Some(("RepoDeactivated", None)), RepoStatus::Deleted => Some(("RepoNotFound", Some("deleted".into()))), _ => None, }; if let Some((code, msg)) = xrpc_err { return Err(xrpc_error(StatusCode::FORBIDDEN, code, msg)); } // return whatever we last recorded; if we haven't synced at all yet, we have nothing to give let Some(commit) = state.root else { return Err(xrpc_error( StatusCode::NOT_FOUND, "RepoNotFound", Some("repo still backfilling".into()), )); }; let Some(atp_commit) = commit.into_atp_commit(req.did) else { return Err(internal_error("repo needs migration")); }; let commit_cid = atp_commit.to_cid().map_err(internal_error)?; Ok(Json(GetLatestCommitOutput { cid: Cid::ipld(commit_cid), rev: atp_commit.rev, })) }