A better Rust ATProto crate
1use clap::Parser;
2use jacquard::CowStr;
3use jacquard::api::app_bsky::feed::post::Post;
4use jacquard::client::{Agent, AgentSessionExt, FileAuthStore};
5use jacquard::oauth::client::OAuthClient;
6use jacquard::oauth::loopback::LoopbackConfig;
7use jacquard::richtext::RichText;
8use jacquard::types::string::Datetime;
9
10#[derive(Parser, Debug)]
11#[command(
12 author,
13 version,
14 about = "Create a post with automatic facet detection"
15)]
16struct Args {
17 /// Handle (e.g., alice.bsky.social), DID, or PDS URL
18 input: CowStr<'static>,
19
20 /// Post text (can include @mentions, #hashtags, URLs, and [markdown](links))
21 #[arg(short, long)]
22 text: String,
23
24 /// Path to auth store file (will be created if missing)
25 #[arg(long, default_value = "/tmp/jacquard-oauth-session.json")]
26 store: String,
27}
28
29#[tokio::main]
30async fn main() -> miette::Result<()> {
31 let args = Args::parse();
32
33 let oauth = OAuthClient::with_default_config(FileAuthStore::new(&args.store));
34 let session = oauth
35 .login_with_local_server(args.input, Default::default(), LoopbackConfig::default())
36 .await?;
37
38 let agent: Agent<_> = Agent::from(session);
39
40 // Parse richtext with automatic facet detection
41 // This detects @mentions, #hashtags, URLs, and [markdown](links)
42 let richtext = RichText::parse(&args.text).build_async(&agent).await?;
43
44 println!(
45 "Detected {} facets:",
46 richtext.facets.as_ref().map(|f| f.len()).unwrap_or(0)
47 );
48 if let Some(facets) = &richtext.facets {
49 for facet in facets {
50 let text_slice =
51 &richtext.text[facet.index.byte_start as usize..facet.index.byte_end as usize];
52 println!(" - \"{}\" ({:?})", text_slice, facet.features);
53 }
54 }
55
56 // Create post with parsed facets
57 let post = Post {
58 text: richtext.text,
59 facets: richtext.facets,
60 created_at: Datetime::now(),
61 embed: None,
62 entities: None,
63 labels: None,
64 langs: None,
65 reply: None,
66 tags: None,
67 extra_data: Default::default(),
68 };
69
70 let output = agent.create_record(post, None).await?;
71 println!("✓ Created post: {}", output.uri);
72
73 Ok(())
74}