import gleam/dynamic/decode.{at, field, map, optional, string, success} import gleam/option.{type Option} pub type BlobRef { BlobRef(link: String) } pub fn decode_blob_ref() -> decode.Decoder(BlobRef) { at(["ref", "$link"], string) |> map(BlobRef) } pub fn blob_ref_to_url(pds_host: String, did: String, blob: BlobRef) -> String { pds_host <> "/xrpc/com.atproto.sync.getBlob?did=" <> did <> "&cid=" <> blob.link } pub type StrongRef { StrongRef(uri: String, cid: String) } pub fn decode_strong_ref() -> decode.Decoder(StrongRef) { use uri <- field("uri", string) use cid <- field("cid", string) success(StrongRef(uri:, cid:)) } pub type Label { Label(val: String) } pub fn decode_label() -> decode.Decoder(Label) { use val <- field("val", string) success(Label(val:)) } pub type Profile { Profile(display_name: Option(String), avatar: Option(BlobRef)) } pub type MiniDoc { MiniDoc(did: String, handle: String, pds: String, signing_key: String) } pub fn decode_mini_doc() -> decode.Decoder(MiniDoc) { use did <- field("did", string) use handle <- field("handle", string) use pds <- field("pds", string) use signing_key <- field("signing_key", string) success(MiniDoc(did:, handle:, pds:, signing_key:)) } pub fn decode_profile() -> decode.Decoder(Profile) { use display_name <- field("displayName", optional(string)) use avatar <- field("avatar", optional(decode_blob_ref())) success(Profile(display_name:, avatar:)) }