-59
Cargo.lock
-59
Cargo.lock
···
157
157
]
158
158
159
159
[[package]]
160
-
name = "async-stream"
161
-
version = "0.3.6"
162
-
source = "registry+https://github.com/rust-lang/crates.io-index"
163
-
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
164
-
dependencies = [
165
-
"async-stream-impl",
166
-
"futures-core",
167
-
"pin-project-lite",
168
-
]
169
-
170
-
[[package]]
171
-
name = "async-stream-impl"
172
-
version = "0.3.6"
173
-
source = "registry+https://github.com/rust-lang/crates.io-index"
174
-
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
175
-
dependencies = [
176
-
"proc-macro2",
177
-
"quote",
178
-
"syn 2.0.106",
179
-
]
180
-
181
-
[[package]]
182
160
name = "async-trait"
183
161
version = "0.1.89"
184
162
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1780
1758
"thiserror 2.0.17",
1781
1759
"tokio",
1782
1760
"url",
1783
-
"urlencoding",
1784
1761
]
1785
1762
1786
1763
[[package]]
···
1835
1812
"serde_json",
1836
1813
"thiserror 2.0.17",
1837
1814
"tokio",
1838
-
"tokio-test",
1839
1815
"tower",
1840
1816
"tower-http",
1841
1817
"tracing",
1842
1818
"tracing-subscriber",
1843
-
"urlencoding",
1844
1819
]
1845
1820
1846
1821
[[package]]
···
1870
1845
"serde_html_form",
1871
1846
"serde_ipld_dagcbor",
1872
1847
"serde_json",
1873
-
"serde_with",
1874
1848
"signature",
1875
1849
"smol_str",
1876
1850
"thiserror 2.0.17",
1877
1851
"tokio",
1878
-
"trait-variant",
1879
1852
"url",
1880
1853
]
1881
1854
···
1916
1889
name = "jacquard-derive"
1917
1890
version = "0.5.1"
1918
1891
dependencies = [
1919
-
"heck 0.5.0",
1920
-
"itertools",
1921
1892
"jacquard-common 0.5.1",
1922
-
"prettyplease",
1923
1893
"proc-macro2",
1924
1894
"quote",
1925
1895
"serde",
1926
1896
"serde_json",
1927
-
"serde_repr",
1928
-
"serde_with",
1929
1897
"syn 2.0.106",
1930
1898
]
1931
1899
···
2000
1968
"clap",
2001
1969
"glob",
2002
1970
"heck 0.5.0",
2003
-
"itertools",
2004
1971
"jacquard-api 0.5.1 (git+https://tangled.org/@nonbinary.computer/jacquard)",
2005
1972
"jacquard-common 0.5.1 (git+https://tangled.org/@nonbinary.computer/jacquard)",
2006
1973
"jacquard-identity 0.5.1 (git+https://tangled.org/@nonbinary.computer/jacquard)",
···
2052
2019
"tokio",
2053
2020
"trait-variant",
2054
2021
"url",
2055
-
"uuid",
2056
2022
"webbrowser",
2057
2023
]
2058
2024
···
3850
3816
]
3851
3817
3852
3818
[[package]]
3853
-
name = "tokio-stream"
3854
-
version = "0.1.17"
3855
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3856
-
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
3857
-
dependencies = [
3858
-
"futures-core",
3859
-
"pin-project-lite",
3860
-
"tokio",
3861
-
]
3862
-
3863
-
[[package]]
3864
-
name = "tokio-test"
3865
-
version = "0.4.4"
3866
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3867
-
checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7"
3868
-
dependencies = [
3869
-
"async-stream",
3870
-
"bytes",
3871
-
"futures-core",
3872
-
"tokio",
3873
-
"tokio-stream",
3874
-
]
3875
-
3876
-
[[package]]
3877
3819
name = "tokio-util"
3878
3820
version = "0.7.16"
3879
3821
source = "registry+https://github.com/rust-lang/crates.io-index"
···
4136
4078
source = "registry+https://github.com/rust-lang/crates.io-index"
4137
4079
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
4138
4080
dependencies = [
4139
-
"getrandom 0.3.3",
4140
4081
"js-sys",
4141
4082
"wasm-bindgen",
4142
4083
]
+1
-1
README.md
+1
-1
README.md
···
81
81
82
82
```
83
83
84
-
If you have `just` installed, you can run the [examples](https://tangled.org/@nonbinary.computer/jacquard/tree/main/examples) using `just example-{example-name} {ARGS}`
84
+
If you have `just` installed, you can run the [examples](https://tangled.org/@nonbinary.computer/jacquard/tree/main/examples) using `just example {example-name} {ARGS}` or `just examples` to see what's available.
85
85
86
86
## Component crates
87
87
+4
-5
crates/jacquard-axum/Cargo.toml
+4
-5
crates/jacquard-axum/Cargo.toml
···
18
18
[[example]]
19
19
name = "axum_server"
20
20
path = "../../examples/axum_server.rs"
21
-
required-features = ["jacquard/fancy"]
22
21
23
22
[dependencies]
24
23
axum = "0.8.6"
25
-
axum-macros = "0.5.0"
26
24
bytes.workspace = true
27
25
jacquard = { version = "0.5", path = "../jacquard" }
28
26
jacquard-common = { version = "0.5", path = "../jacquard-common", features = ["reqwest-client"] }
···
38
36
tokio.workspace = true
39
37
tower-http = { version = "0.6.6", features = ["trace", "tracing"] }
40
38
tracing = "0.1.41"
41
-
tracing-subscriber = { version = "0.3.20", features = ["env-filter", "time"] }
42
-
urlencoding.workspace = true
43
39
44
40
[features]
45
41
default = ["service-auth"]
46
42
service-auth = ["jacquard-common/service-auth", "dep:jacquard-identity", "dep:multibase"]
47
43
48
44
[dev-dependencies]
45
+
axum-macros = "0.5.0"
49
46
axum-test = "18.1.0"
50
47
base64.workspace = true
51
48
chrono.workspace = true
52
49
k256 = { version = "0.13", features = ["ecdsa"] }
50
+
miette = { workspace = true, features = ["fancy"] }
53
51
rand = "0.8"
54
52
reqwest.workspace = true
55
53
serde_json.workspace = true
56
-
tokio-test = "0.4.4"
54
+
#tokio-test = "0.4.4"
57
55
tower = { version = "0.5", features = ["util"] }
56
+
tracing-subscriber = { version = "0.3.20", features = ["env-filter", "time"] }
-2
crates/jacquard-common/Cargo.toml
-2
crates/jacquard-common/Cargo.toml
···
29
29
serde.workspace = true
30
30
serde_html_form.workspace = true
31
31
serde_json.workspace = true
32
-
serde_with.workspace = true
33
32
smol_str.workspace = true
34
33
thiserror.workspace = true
35
34
url.workspace = true
···
38
37
tokio = { workspace = true, features = ["sync"] }
39
38
reqwest = { workspace = true, optional = true, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] }
40
39
serde_ipld_dagcbor.workspace = true
41
-
trait-variant.workspace = true
42
40
signature = { version = "2", optional = true }
43
41
44
42
[features]
+2
-8
crates/jacquard-derive/Cargo.toml
+2
-8
crates/jacquard-derive/Cargo.toml
···
15
15
proc-macro = true
16
16
17
17
[dependencies]
18
-
heck.workspace = true
19
-
itertools.workspace = true
20
-
prettyplease.workspace = true
21
18
proc-macro2.workspace = true
22
19
quote.workspace = true
23
-
serde.workspace = true
24
-
serde_json.workspace = true
25
-
serde_repr.workspace = true
26
-
serde_with.workspace = true
27
20
syn.workspace = true
28
-
29
21
30
22
[dev-dependencies]
31
23
jacquard-common = { version = "0.5", path = "../jacquard-common" }
24
+
serde.workspace = true
25
+
serde_json.workspace = true
+1
-1
crates/jacquard-lexicon/Cargo.toml
+1
-1
crates/jacquard-lexicon/Cargo.toml
···
24
24
clap.workspace = true
25
25
glob = "0.3"
26
26
heck.workspace = true
27
-
itertools.workspace = true
27
+
#itertools.workspace = true
28
28
jacquard-api = { version = "0.5", git = "https://tangled.org/@nonbinary.computer/jacquard" }
29
29
jacquard-common = { version = "0.5", git = "https://tangled.org/@nonbinary.computer/jacquard" }
30
30
jacquard-identity = { version = "0.5", git = "https://tangled.org/@nonbinary.computer/jacquard" }
-1
crates/jacquard-oauth/Cargo.toml
-1
crates/jacquard-oauth/Cargo.toml
+5
-14
crates/jacquard/Cargo.toml
+5
-14
crates/jacquard/Cargo.toml
···
23
23
# All captured generated lexicon API bindings
24
24
api_all = ["api_full", "jacquard-api/ufos"]
25
25
dns = ["jacquard-identity/dns"]
26
-
# Pretty debug prints for examples
27
-
fancy = ["miette/fancy"]
28
26
# Propagate loopback to oauth (server + browser helper)
29
27
loopback = ["jacquard-oauth/loopback", "jacquard-oauth/browser-open"]
30
28
···
32
30
[[example]]
33
31
name = "oauth_timeline"
34
32
path = "../../examples/oauth_timeline.rs"
35
-
required-features = ["fancy"]
36
33
37
34
[[example]]
38
35
name = "create_post"
39
36
path = "../../examples/create_post.rs"
40
-
required-features = ["fancy"]
41
37
42
38
[[example]]
43
39
name = "post_with_image"
44
40
path = "../../examples/post_with_image.rs"
45
-
required-features = ["fancy"]
46
41
47
42
[[example]]
48
43
name = "update_profile"
49
44
path = "../../examples/update_profile.rs"
50
-
required-features = ["fancy"]
51
45
52
46
[[example]]
53
47
name = "public_atproto_feed"
···
56
50
[[example]]
57
51
name = "create_whitewind_post"
58
52
path = "../../examples/create_whitewind_post.rs"
59
-
required-features = ["fancy", ]
60
53
61
54
[[example]]
62
55
name = "read_whitewind_post"
63
56
path = "../../examples/read_whitewind_post.rs"
64
-
required-features = ["fancy"]
65
57
66
58
[[example]]
67
59
name = "read_tangled_repo"
68
60
path = "../../examples/read_tangled_repo.rs"
69
-
required-features = ["fancy"]
70
61
71
62
[[example]]
72
63
name = "resolve_did"
73
64
path = "../../examples/resolve_did.rs"
74
-
required-features = ["fancy"]
75
65
76
66
[[example]]
77
67
name = "update_preferences"
78
68
path = "../../examples/update_preferences.rs"
79
-
required-features = ["fancy"]
80
69
81
70
[dependencies]
82
71
jacquard-api = { version = "0.5", path = "../jacquard-api" }
···
88
77
bon.workspace = true
89
78
async-trait.workspace = true
90
79
bytes.workspace = true
91
-
clap.workspace = true
92
80
http.workspace = true
93
81
miette = { workspace = true }
94
82
reqwest = { workspace = true, features = ["charset", "http2", "json", "system-proxy", "gzip", "rustls-tls"] }
···
101
89
url.workspace = true
102
90
smol_str.workspace = true
103
91
percent-encoding.workspace = true
104
-
urlencoding.workspace = true
105
92
jose-jwk = { workspace = true, features = ["p256"] }
106
93
p256 = { workspace = true, features = ["ecdsa"] }
107
94
rand_core.workspace = true
108
95
96
+
[dev-dependencies]
97
+
clap.workspace = true
98
+
miette = { workspace = true, features = ["fancy"] }
99
+
109
100
[package.metadata.docs.rs]
110
-
features = [ "api_all", "derive", "dns", "fancy", "loopback" ]
101
+
features = [ "api_all", "derive", "dns", "loopback" ]
+1
-6
examples/axum_server.rs
+1
-6
examples/axum_server.rs
···
1
1
use std::sync::Arc;
2
2
3
-
use axum::{
4
-
Json, Router,
5
-
extract::State,
6
-
http::{StatusCode, header},
7
-
response::IntoResponse,
8
-
};
3
+
use axum::{Json, Router, extract::State, http::StatusCode, response::IntoResponse};
9
4
use jacquard::{
10
5
api::com_atproto::identity::resolve_did::{ResolveDidOutput, ResolveDidRequest},
11
6
identity::{JacquardResolver, resolver::IdentityResolver},
+2
-5
examples/create_post.rs
+2
-5
examples/create_post.rs
···
1
1
use clap::Parser;
2
+
use jacquard::CowStr;
2
3
use jacquard::api::app_bsky::feed::post::Post;
3
-
use jacquard::client::{Agent, FileAuthStore};
4
-
use jacquard::oauth::atproto::AtprotoClientMetadata;
4
+
use jacquard::client::{Agent, AgentSessionExt, FileAuthStore};
5
5
use jacquard::oauth::client::OAuthClient;
6
6
use jacquard::oauth::loopback::LoopbackConfig;
7
7
use jacquard::types::string::Datetime;
8
-
use jacquard::xrpc::XrpcClient;
9
-
use jacquard::CowStr;
10
-
use miette::IntoDiagnostic;
11
8
12
9
#[derive(Parser, Debug)]
13
10
#[command(author, version, about = "Create a simple post")]
+3
-5
examples/create_whitewind_post.rs
+3
-5
examples/create_whitewind_post.rs
···
1
1
use clap::Parser;
2
2
use jacquard::CowStr;
3
3
use jacquard::api::com_whtwnd::blog::entry::Entry;
4
-
use jacquard::client::{Agent, FileAuthStore};
5
-
use jacquard::oauth::atproto::AtprotoClientMetadata;
4
+
use jacquard::client::{Agent, AgentSessionExt, FileAuthStore};
6
5
use jacquard::oauth::client::OAuthClient;
7
6
use jacquard::oauth::loopback::LoopbackConfig;
8
7
use jacquard::types::string::Datetime;
9
-
use jacquard::xrpc::XrpcClient;
10
8
use miette::IntoDiagnostic;
11
9
use url::Url;
12
10
···
59
57
extra_data: Default::default(),
60
58
};
61
59
62
-
let mut output = agent.create_record(entry, None).await?;
60
+
let output = agent.create_record(entry, None).await?;
63
61
println!("Created WhiteWind blog post: {}", output.uri);
64
-
let url = Url::parse(format!(
62
+
let url = Url::parse(&format!(
65
63
"https://whtwnd.nat.vg/{}/{}",
66
64
output.uri.authority(),
67
65
output.uri.rkey().map(|r| r.as_ref()).unwrap_or("")
+1
-3
examples/post_with_image.rs
+1
-3
examples/post_with_image.rs
···
2
2
use jacquard::CowStr;
3
3
use jacquard::api::app_bsky::embed::images::{Image, Images};
4
4
use jacquard::api::app_bsky::feed::post::{Post, PostEmbed};
5
-
use jacquard::client::{Agent, FileAuthStore};
6
-
use jacquard::oauth::atproto::AtprotoClientMetadata;
5
+
use jacquard::client::{Agent, AgentSessionExt, FileAuthStore};
7
6
use jacquard::oauth::client::OAuthClient;
8
7
use jacquard::oauth::loopback::LoopbackConfig;
9
8
use jacquard::types::blob::MimeType;
10
9
use jacquard::types::string::Datetime;
11
-
use jacquard::xrpc::XrpcClient;
12
10
use miette::IntoDiagnostic;
13
11
use std::path::PathBuf;
14
12
+1
-1
examples/read_tangled_repo.rs
+1
-1
examples/read_tangled_repo.rs
+5
-2
examples/read_whitewind_post.rs
+5
-2
examples/read_whitewind_post.rs
···
1
1
use clap::Parser;
2
2
use jacquard::api::com_whtwnd::blog::entry::Entry;
3
-
use jacquard::client::BasicClient;
3
+
use jacquard::client::{AgentSessionExt, BasicClient};
4
4
use jacquard::types::string::AtUri;
5
5
6
6
#[derive(Parser, Debug)]
···
27
27
28
28
println!("📚 WhiteWind Blog Entry\n");
29
29
println!("URI: {}", output.uri);
30
-
println!("Title: {}", output.value.title.as_deref().unwrap_or("[Untitled]"));
30
+
println!(
31
+
"Title: {}",
32
+
output.value.title.as_deref().unwrap_or("[Untitled]")
33
+
);
31
34
if let Some(subtitle) = &output.value.subtitle {
32
35
println!("Subtitle: {}", subtitle);
33
36
}
+1
-4
examples/update_profile.rs
+1
-4
examples/update_profile.rs
···
1
1
use clap::Parser;
2
2
use jacquard::CowStr;
3
3
use jacquard::api::app_bsky::actor::profile::Profile;
4
-
use jacquard::client::{Agent, FileAuthStore};
5
-
use jacquard::oauth::atproto::AtprotoClientMetadata;
4
+
use jacquard::client::{Agent, AgentSessionExt, FileAuthStore};
6
5
use jacquard::oauth::client::OAuthClient;
7
6
use jacquard::oauth::loopback::LoopbackConfig;
8
7
use jacquard::types::string::AtUri;
9
-
use jacquard::xrpc::XrpcClient;
10
-
use miette::IntoDiagnostic;
11
8
12
9
#[derive(Parser, Debug)]
13
10
#[command(author, version, about = "Update profile display name and description")]
+48
-37
justfile
+48
-37
justfile
···
13
13
watch *ARGS:
14
14
bacon --job run -- -- {{ ARGS }}
15
15
16
-
# Run the OAuth timeline example
17
-
example-oauth *ARGS:
18
-
cargo run -p jacquard --example oauth_timeline --features fancy -- {{ARGS}}
16
+
update-api:
17
+
cargo run -p jacquard-lexicon --bin lex-fetch -- -v
19
18
20
-
# Create a simple post
21
-
example-create-post *ARGS:
22
-
cargo run -p jacquard --example create_post --features fancy -- {{ARGS}}
19
+
generate-api:
20
+
cargo run -p jacquard-lexicon --bin jacquard-codegen -- -i crates/jacquard-api/lexicons -o crates/jacquard-api/src -r crate
23
21
24
-
# Create a post with an image
25
-
example-post-image *ARGS:
26
-
cargo run -p jacquard --example post_with_image --features fancy -- {{ARGS}}
22
+
lex-gen *ARGS:
23
+
cargo run -p jacquard-lexicon --bin lex-fetch -- {{ARGS}}
27
24
28
-
# Update profile display name and description
29
-
example-update-profile *ARGS:
30
-
cargo run -p jacquard --example update_profile --features fancy -- {{ARGS}}
25
+
lex-fetch *ARGS:
26
+
cargo run -p jacquard-lexicon --bin lex-fetch -- --no-codegen {{ARGS}}
31
27
32
-
# Fetch public AT Protocol feed (no auth)
33
-
example-public-feed:
34
-
cargo run -p jacquard --example public_atproto_feed
28
+
codegen *ARGS:
29
+
cargo run -p jacquard-lexicon --bin jacquard-codegen -- -r crate {{ARGS}}
35
30
36
-
# Create a WhiteWind blog post
37
-
example-whitewind-create *ARGS:
38
-
cargo run -p jacquard --example create_whitewind_post --features fancy -- {{ARGS}}
31
+
# List all available examples
32
+
examples:
33
+
#!/usr/bin/env bash
34
+
echo "jacquard examples:"
35
+
for file in "examples"/*.rs; do
36
+
name=$(basename "$file" .rs)
37
+
echo " - $name"
38
+
done
39
+
echo ""
40
+
echo "jacquard-axum examples:"
41
+
cargo metadata --format-version=1 --no-deps | \
42
+
jq -r '.packages[] | select(.name == "jacquard-axum") | .targets[] | select(.kind[] == "example") | .name' | \
43
+
sed 's/^/ - /'
44
+
echo ""
45
+
echo "Usage: just example <name> [ARGS...]"
39
46
40
-
# Read a WhiteWind blog post
41
-
example-whitewind-read *ARGS:
42
-
cargo run -p jacquard --example read_whitewind_posts --features fancy -- {{ARGS}}
43
-
44
-
# Read info about a Tangled git repository
45
-
example-tangled-repo *ARGS:
46
-
cargo run -p jacquard --example read_tangled_repo --features fancy -- {{ARGS}}
47
-
48
-
# Resolve a handle to its DID document
49
-
example-resolve-did *ARGS:
50
-
cargo run -p jacquard --example resolve_did -- {{ARGS}}
51
-
52
-
# Update Bluesky preferences
53
-
example-update-preferences *ARGS:
54
-
cargo run -p jacquard --example update_preferences --features fancy -- {{ARGS}}
55
-
56
-
# Run the Axum server example
57
-
example-axum:
58
-
cargo run -p jacquard-axum --example axum_server --features jacquard/fancy
47
+
# Run an example by name (auto-detects package)
48
+
example NAME *ARGS:
49
+
#!/usr/bin/env bash
50
+
if [ -f "examples/{{NAME}}.rs" ]; then
51
+
cargo run -p jacquard --example {{NAME}} -- {{ARGS}}
52
+
elif cargo metadata --format-version=1 --no-deps | \
53
+
jq -e '.packages[] | select(.name == "jacquard-axum") | .targets[] | select(.kind[] == "example" and .name == "{{NAME}}")' > /dev/null; then
54
+
cargo run -p jacquard-axum --example {{NAME}} -- {{ARGS}}
55
+
else
56
+
echo "Example '{{NAME}}' not found."
57
+
echo ""
58
+
echo "jacquard examples:"
59
+
for file in "examples"/*.rs; do
60
+
name=$(basename "$file" .rs)
61
+
echo " - $name"
62
+
done
63
+
echo ""
64
+
echo "jacquard-axum examples:"
65
+
cargo metadata --format-version=1 --no-deps | \
66
+
jq -r '.packages[] | select(.name == "jacquard-axum") | .targets[] | select(.kind[] == "example") | .name' | \
67
+
sed 's/^/ - /'
68
+
exit 1
69
+
fi