1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Deserialize)]
10pub struct FeedConfig {
11 pub id: String,
13 pub display_name: String,
15 pub description: Option<String>,
17 pub avatar: Option<String>,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct FeedSkeleton {
24 pub feed: Vec<SkeletonItem>,
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub cursor: Option<String>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct SkeletonItem {
34 pub post: String,
36}
37
38impl SkeletonItem {
39 pub fn new(post_uri: impl Into<String>) -> Self {
41 Self {
42 post: post_uri.into(),
43 }
44 }
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct FeedDescription {
50 pub uri: String,
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub cid: Option<String>,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct DescribeFeedGeneratorResponse {
60 pub did: String,
62 pub feeds: Vec<FeedDescription>,
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn skeleton_item_new() {
72 let item = SkeletonItem::new("at://did:plc:abc/app.bsky.feed.post/123");
73 assert_eq!(item.post, "at://did:plc:abc/app.bsky.feed.post/123");
74 }
75
76 #[test]
77 fn feed_skeleton_serializes_without_cursor() {
78 let skeleton = FeedSkeleton {
79 feed: vec![SkeletonItem::new("at://did:plc:abc/app.bsky.feed.post/1")],
80 cursor: None,
81 };
82 let json = serde_json::to_value(&skeleton).unwrap();
83 assert!(json.get("cursor").is_none());
84 assert_eq!(
85 json["feed"][0]["post"],
86 "at://did:plc:abc/app.bsky.feed.post/1"
87 );
88 }
89
90 #[test]
91 fn feed_skeleton_serializes_with_cursor() {
92 let skeleton = FeedSkeleton {
93 feed: vec![],
94 cursor: Some("abc123".to_string()),
95 };
96 let json = serde_json::to_value(&skeleton).unwrap();
97 assert_eq!(json["cursor"], "abc123");
98 }
99
100 #[test]
101 fn describe_response_serializes() {
102 let resp = DescribeFeedGeneratorResponse {
103 did: "did:web:feeds.example.com".to_string(),
104 feeds: vec![FeedDescription {
105 uri: "at://did:web:feeds.example.com/app.bsky.feed.generator/my-feed".to_string(),
106 cid: None,
107 }],
108 };
109 let json = serde_json::to_value(&resp).unwrap();
110 assert_eq!(json["did"], "did:web:feeds.example.com");
111 assert_eq!(json["feeds"].as_array().unwrap().len(), 1);
112 assert!(json["feeds"][0].get("cid").is_none());
113 }
114}