···1515exclude = [".direnv"]
161617171818-description = "A simple Rust project using Nix"
1919-1818+description = "Simple and powerful AT Protocol client library for Rust"
20192120# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
22212322[workspace.dependencies]
2323+# CLI
2424clap = { version = "4.5", features = ["derive"] }
2525+2626+# Serialization
2727+serde = { version = "1.0", features = ["derive"] }
2828+serde_json = "1.0"
2929+serde_with = "3.14"
3030+serde_html_form = "0.2"
3131+serde_ipld_dagcbor = "0.6"
3232+serde_repr = "0.1"
3333+3434+# Error handling
3535+miette = "7.6"
3636+thiserror = "2.0"
3737+3838+# Data types
3939+bytes = "1.10"
4040+smol_str = { version = "0.3", features = ["serde"] }
4141+url = "2.5"
4242+4343+# Proc macros
4444+proc-macro2 = "1.0"
4545+quote = "1.0"
4646+syn = "2.0"
4747+heck = "0.5"
4848+itertools = "0.14"
4949+prettyplease = "0.2"
5050+5151+# HTTP
5252+http = "1.3"
5353+reqwest = { version = "0.12", default-features = false }
+71-26
README.md
···2233A suite of Rust crates for the AT Protocol.
4455+## Example
66+77+Dead simple api client. Logs in, prints the latest 5 posts from your timeline.
88+99+```rust
1010+use clap::Parser;
1111+use jacquard::CowStr;
1212+use jacquard::api::app_bsky::feed::get_timeline::GetTimeline;
1313+use jacquard::api::com_atproto::server::create_session::CreateSession;
1414+use jacquard::client::{AuthenticatedClient, Session, XrpcClient};
1515+use miette::IntoDiagnostic;
1616+1717+#[derive(Parser, Debug)]
1818+#[command(author, version, about = "Jacquard - AT Protocol client demo")]
1919+struct Args {
2020+ /// Username/handle (e.g., alice.mosphere.at)
2121+ #[arg(short, long)]
2222+ username: CowStr<'static>,
2323+2424+ /// PDS URL (e.g., https://bsky.social)
2525+ #[arg(long, default_value = "https://bsky.social")]
2626+ pds: CowStr<'static>,
2727+2828+ /// App password
2929+ #[arg(short, long)]
3030+ password: CowStr<'static>,
3131+}
3232+3333+#[tokio::main]
3434+async fn main() -> miette::Result<()> {
3535+ let args = Args::parse();
3636+3737+ // Create HTTP client
3838+ let mut client = AuthenticatedClient::new(reqwest::Client::new(), args.pds);
3939+4040+ // Create session
4141+ let session = Session::from(
4242+ client
4343+ .send(
4444+ CreateSession::new()
4545+ .identifier(args.username)
4646+ .password(args.password)
4747+ .build(),
4848+ )
4949+ .await?
5050+ .into_output()?,
5151+ );
5252+5353+ println!("logged in as {} ({})", session.handle, session.did);
5454+ client.set_session(session);
5555+5656+ // Fetch timeline
5757+ println!("\nfetching timeline...");
5858+ let timeline = client
5959+ .send(GetTimeline::new().limit(5).build())
6060+ .await?
6161+ .into_output()?;
6262+6363+ println!("\ntimeline ({} posts):", timeline.feed.len());
6464+ for (i, post) in timeline.feed.iter().enumerate() {
6565+ println!("\n{}. by {}", i + 1, post.post.author.handle);
6666+ println!(
6767+ " {}",
6868+ serde_json::to_string_pretty(&post.post.record).into_diagnostic()?
6969+ );
7070+ }
7171+7272+ Ok(())
7373+}
7474+```
7575+576## Goals
677778- Validated, spec-compliant, easy to work with, and performant baseline types (including typed at:// uris)
···29100```
3010131102There's also a [`justfile`](https://just.systems/) for Makefile-esque commands to be run inside of the devShell, and you can generally `cargo ...` or `just ...` whatever just fine if you don't want to use Nix and have the prerequisites installed.
3232-3333-3434-3535-### String types
3636-Something of a note to self. Developing a pattern with the string types (may macro-ify at some point). Each needs:
3737-- new(): constructing from a string slice with the right lifetime that borrows
3838-- new_owned(): constructing from an impl AsRef<str>, taking ownership
3939-- new_static(): construction from a &'static str, using SmolStr's/CowStr's new_static() constructor to not allocate
4040-- raw(): same as new() but panics instead of erroring
4141-- unchecked(): same as new() but doesn't validate. marked unsafe.
4242-- as_str(): does what it says on the tin
4343-#### Traits:
4444-- Serialize + Deserialize (custom impl for latter, sometimes for former)
4545-- FromStr
4646-- Display
4747-- Debug, PartialEq, Eq, Hash, Clone
4848-- From<T> for String, CowStr, SmolStr,
4949-- From<String>, From<CowStr>, From<SmolStr>, or TryFrom if likely enough to fail in practice to make panics common
5050-- AsRef<str>
5151-- Deref with Target = str (usually)
5252-5353-Use `#[repr(transparent)]` as much as possible. Main exception is at-uri type and components.
5454-Use SmolStr directly as the inner type if most or all of the instances will be under 24 bytes, save lifetime headaches.
5555-Use CowStr for longer to allow for borrowing from input.
5656-5757-TODO: impl IntoStatic trait to take ownership of string types