A better Rust ATProto crate

add app password based example

vielle.dev 1fd9310a 51b190cd

verified
Changed files
+76 -6
crates
jacquard
examples
+27 -6
crates/jacquard/Cargo.toml
··· 17 # Minimal API bindings 18 api = ["jacquard-api/minimal"] 19 # Bluesky API bindings 20 - api_bluesky = ["api", "jacquard-api/bluesky" ] 21 # Bluesky API bindings, plus a curated selection of community lexicons 22 - api_full = ["api", "jacquard-api/bluesky", "jacquard-api/other", "jacquard-api/lexicon_community"] 23 # All captured generated lexicon API bindings 24 api_all = ["api_full", "jacquard-api/ufos"] 25 26 # Propagate loopback to oauth (server + browser helper) 27 loopback = ["jacquard-oauth/loopback", "jacquard-oauth/browser-open"] 28 # Enable tracing instrumentation 29 - tracing = ["dep:tracing", "jacquard-common/tracing", "jacquard-oauth/tracing", "jacquard-identity/tracing"] 30 dns = ["jacquard-identity/dns"] 31 streaming = ["jacquard-common/streaming"] 32 websocket = ["jacquard-common/websocket"] ··· 83 path = "../../examples/streaming_download.rs" 84 required-features = ["api_bluesky", "streaming"] 85 86 87 [dependencies] 88 jacquard-api = { version = "0.5", path = "../jacquard-api" } 89 - jacquard-common = { version = "0.5", path = "../jacquard-common", features = ["reqwest-client"] } 90 jacquard-oauth = { version = "0.5", path = "../jacquard-oauth" } 91 jacquard-derive = { version = "0.5", path = "../jacquard-derive", optional = true } 92 jacquard-identity = { version = "0.5", path = "../jacquard-identity" } ··· 112 tracing = { workspace = true, optional = true } 113 114 [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 115 - reqwest = { workspace = true, features = ["http2", "system-proxy", "rustls-tls"] } 116 tokio = { workspace = true, features = ["macros", "rt-multi-thread", "fs"] } 117 118 [target.'cfg(target_family = "wasm")'.dependencies] ··· 123 miette = { workspace = true, features = ["fancy"] } 124 125 [package.metadata.docs.rs] 126 - features = [ "api_all", "derive", "dns", "loopback" ]
··· 17 # Minimal API bindings 18 api = ["jacquard-api/minimal"] 19 # Bluesky API bindings 20 + api_bluesky = ["api", "jacquard-api/bluesky"] 21 # Bluesky API bindings, plus a curated selection of community lexicons 22 + api_full = [ 23 + "api", 24 + "jacquard-api/bluesky", 25 + "jacquard-api/other", 26 + "jacquard-api/lexicon_community", 27 + ] 28 # All captured generated lexicon API bindings 29 api_all = ["api_full", "jacquard-api/ufos"] 30 31 # Propagate loopback to oauth (server + browser helper) 32 loopback = ["jacquard-oauth/loopback", "jacquard-oauth/browser-open"] 33 # Enable tracing instrumentation 34 + tracing = [ 35 + "dep:tracing", 36 + "jacquard-common/tracing", 37 + "jacquard-oauth/tracing", 38 + "jacquard-identity/tracing", 39 + ] 40 dns = ["jacquard-identity/dns"] 41 streaming = ["jacquard-common/streaming"] 42 websocket = ["jacquard-common/websocket"] ··· 93 path = "../../examples/streaming_download.rs" 94 required-features = ["api_bluesky", "streaming"] 95 96 + [[example]] 97 + name = "app_password_create_post" 98 + path = "../../examples/app_password_create_post.rs" 99 + required-features = ["api_bluesky"] 100 + 101 102 [dependencies] 103 jacquard-api = { version = "0.5", path = "../jacquard-api" } 104 + jacquard-common = { version = "0.5", path = "../jacquard-common", features = [ 105 + "reqwest-client", 106 + ] } 107 jacquard-oauth = { version = "0.5", path = "../jacquard-oauth" } 108 jacquard-derive = { version = "0.5", path = "../jacquard-derive", optional = true } 109 jacquard-identity = { version = "0.5", path = "../jacquard-identity" } ··· 129 tracing = { workspace = true, optional = true } 130 131 [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 132 + reqwest = { workspace = true, features = [ 133 + "http2", 134 + "system-proxy", 135 + "rustls-tls", 136 + ] } 137 tokio = { workspace = true, features = ["macros", "rt-multi-thread", "fs"] } 138 139 [target.'cfg(target_family = "wasm")'.dependencies] ··· 144 miette = { workspace = true, features = ["fancy"] } 145 146 [package.metadata.docs.rs] 147 + features = ["api_all", "derive", "dns", "loopback"]
+49
examples/app_password_create_post.rs
···
··· 1 + use clap::Parser; 2 + use jacquard::CowStr; 3 + use jacquard::api::app_bsky::feed::post::Post; 4 + use jacquard::client::{Agent, AgentSessionExt, MemoryCredentialSession}; 5 + use jacquard::types::string::Datetime; 6 + 7 + #[derive(Parser, Debug)] 8 + #[command(author, version, about = "Create a simple post")] 9 + struct Args { 10 + /// Handle (e.g., alice.bsky.social) or DID 11 + input: CowStr<'static>, 12 + 13 + /// App Password 14 + password: CowStr<'static>, 15 + 16 + /// Post text 17 + #[arg(short, long)] 18 + text: String, 19 + } 20 + 21 + #[tokio::main] 22 + async fn main() -> miette::Result<()> { 23 + let args = Args::parse(); 24 + 25 + let (session, auth) = 26 + MemoryCredentialSession::authenticated(args.input, args.password, None).await?; 27 + println!("Signed in as {}", auth.handle); 28 + 29 + let agent: Agent<_> = Agent::from(session); 30 + 31 + // Create a simple text post using the Agent convenience method 32 + let post = Post { 33 + text: CowStr::from(args.text), 34 + created_at: Datetime::now(), 35 + embed: None, 36 + entities: None, 37 + facets: None, 38 + labels: None, 39 + langs: None, 40 + reply: None, 41 + tags: None, 42 + extra_data: Default::default(), 43 + }; 44 + 45 + let output = agent.create_record(post, None).await?; 46 + println!("✓ Created post: {}", output.uri); 47 + 48 + Ok(()) 49 + }