Radish alpha
r
Radicle desktop app
Radicle
Git (anonymous pull)
Log in to clone via SSH
Add Release/Artifact ts-rs DTOs
Daniel Norman committed 7 days ago
commit 20cf6ba44a9b2daac19fe7218162e803175287ab
parent 97f078f090e136b7a48fb4a6cd932105d9c3ba73
2 files changed +151 -0
modified crates/radicle-types/src/cobs.rs
@@ -11,6 +11,7 @@ use radicle::node::{Alias, AliasStore};
pub mod diff;
pub mod issue;
pub mod job;
+
pub mod release;
pub mod repo;
pub mod stream;
pub mod thread;
added crates/radicle-types/src/cobs/release.rs
@@ -0,0 +1,150 @@
+
use std::collections::BTreeMap;
+

+
use radicle::identity::Did;
+
use radicle::node::AliasStore;
+
use radicle_artifact::share::cid_utils;
+
use serde::Serialize;
+
use ts_rs::TS;
+

+
use crate::cobs;
+

+
#[derive(Clone, Serialize, TS, Debug)]
+
#[serde(rename_all = "camelCase")]
+
#[ts(export)]
+
#[ts(export_to = "cob/release/")]
+
pub struct Release {
+
    #[ts(as = "String")]
+
    pub id: radicle_artifact::ReleaseId,
+
    #[ts(as = "String")]
+
    pub oid: radicle::git::Oid,
+
    #[ts(type = "number")]
+
    pub timestamp: u64,
+
    pub artifacts: Vec<Artifact>,
+
}
+

+
#[derive(Clone, Serialize, TS, Debug)]
+
#[serde(rename_all = "camelCase")]
+
#[ts(export)]
+
#[ts(export_to = "cob/release/")]
+
pub struct Artifact {
+
    pub cid: String,
+
    pub name: String,
+
    pub kind: ArtifactKind,
+
    pub author: cobs::Author,
+
    pub locations: Vec<Location>,
+
    pub attestations: Vec<cobs::Author>,
+
    pub redactions: Vec<Redaction>,
+
    /// True when at least one of the location URLs we (the local DID) wrote
+
    /// to this artifact uses the `iroh://` scheme — i.e. we are advertising
+
    /// ourselves as an iroh provider for it.
+
    pub shared_by_us: bool,
+
}
+

+
#[derive(Clone, Serialize, TS, Debug)]
+
#[serde(rename_all = "camelCase")]
+
#[ts(export)]
+
#[ts(export_to = "cob/release/")]
+
pub enum ArtifactKind {
+
    Blob,
+
    Collection,
+
    Unknown,
+
}
+

+
#[derive(Clone, Serialize, TS, Debug)]
+
#[serde(rename_all = "camelCase")]
+
#[ts(export)]
+
#[ts(export_to = "cob/release/")]
+
pub struct Location {
+
    pub peer: cobs::Author,
+
    pub urls: Vec<String>,
+
}
+

+
#[derive(Clone, Serialize, TS, Debug)]
+
#[serde(rename_all = "camelCase")]
+
#[ts(export)]
+
#[ts(export_to = "cob/release/")]
+
pub struct Redaction {
+
    pub peer: cobs::Author,
+
    pub reason: String,
+
}
+

+
impl Release {
+
    pub fn new(
+
        id: radicle_artifact::ReleaseId,
+
        release: &radicle_artifact::Release,
+
        our_did: &Did,
+
        aliases: &impl AliasStore,
+
    ) -> Self {
+
        let artifacts = release
+
            .artifacts()
+
            .iter()
+
            .map(|(cid, artifact)| Artifact::new(cid, artifact, our_did, aliases))
+
            .collect();
+

+
        Self {
+
            id,
+
            oid: *release.oid(),
+
            timestamp: release.timestamp(),
+
            artifacts,
+
        }
+
    }
+
}
+

+
impl Artifact {
+
    pub fn new(
+
        cid: &cid::Cid,
+
        artifact: &radicle_artifact::Artifact,
+
        our_did: &Did,
+
        aliases: &impl AliasStore,
+
    ) -> Self {
+
        let kind = match cid_utils::artifact_kind(cid) {
+
            Ok(cid_utils::ArtifactKind::Blob) => ArtifactKind::Blob,
+
            Ok(cid_utils::ArtifactKind::Collection) => ArtifactKind::Collection,
+
            Err(_) => ArtifactKind::Unknown,
+
        };
+

+
        let locations = artifact
+
            .locations()
+
            .iter()
+
            .map(|(did, urls)| Location {
+
                peer: cobs::Author::new(did, aliases),
+
                urls: urls.iter().map(|u| u.to_string()).collect(),
+
            })
+
            .collect();
+

+
        let attestations = artifact
+
            .attestations()
+
            .iter()
+
            .map(|did| cobs::Author::new(did, aliases))
+
            .collect();
+

+
        let redactions = artifact
+
            .redactions()
+
            .iter()
+
            .map(|(did, reason)| Redaction {
+
                peer: cobs::Author::new(did, aliases),
+
                reason: reason.clone(),
+
            })
+
            .collect();
+

+
        let shared_by_us = artifact
+
            .locations_of(our_did)
+
            .is_some_and(|urls| urls.iter().any(|u| u.scheme() == "iroh"));
+

+
        Self {
+
            cid: cid.to_string(),
+
            name: artifact.name().to_string(),
+
            kind,
+
            author: cobs::Author::new(artifact.author(), aliases),
+
            locations,
+
            attestations,
+
            redactions,
+
            shared_by_us,
+
        }
+
    }
+
}
+

+
// Quiet the dead-code warning: this map alias keeps the upstream type names
+
// aligned with the DTO at a glance, and may be used later by trait helpers.
+
#[allow(dead_code)]
+
pub(crate) type LocationMap = BTreeMap<Did, std::collections::BTreeSet<url::Url>>;