1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use atproto_identity::key::{KeyType, generate_key};
use atproto_oauth::workflow::OAuthClient;
use axum::Json;
use axum::routing::get;
use serde_json::json;
use zkwid_dev::{Devnet, N_HOST};
#[tokio::test(flavor = "multi_thread")]
async fn devnet() -> anyhow::Result<()> {
let devnet = Devnet::start().await?;
assert!(devnet.user.did.starts_with("did:plc:"));
let bytes = b"zkwid devnet blob".to_vec();
let blob = devnet.upload_blob(&bytes, "application/octet-stream").await?;
assert_eq!(blob.link.link, atproto_dasl::compute_raw_cid(&bytes).to_string());
assert_eq!(blob.size, bytes.len() as u64);
let collection = "at.zkwid.demo.log";
let record = json!({ "$type": collection, "text": "hello", "createdAt": "2026-11-05T00:00:00.000Z" });
let strong = devnet.put_record(collection, "one", &record).await?;
assert_eq!(strong.uri, format!("at://{}/{collection}/one", devnet.user.did));
let (value, cid) = devnet.get_record(collection, "one").await?.expect("record");
assert_eq!(value["text"], "hello");
assert_eq!(cid, strong.cid);
let listed = devnet.list_records(collection).await?;
assert_eq!(listed.len(), 1);
assert_eq!(listed[0].0, strong.uri);
devnet.delete_record(collection, "one").await?;
assert!(devnet.get_record(collection, "one").await?.is_none());
assert!(devnet.list_records(collection).await?.is_empty());
let client_key = generate_key(KeyType::P256Private)?;
let client_id = format!("https://{N_HOST}/oauth-client-metadata.json");
let redirect_uri = format!("https://{N_HOST}/cb");
let scope = "atproto repo:at.zkwid.demo.log";
let metadata = json!({
"client_id": client_id,
"client_name": "zkwid devnet test",
"client_uri": format!("https://{N_HOST}"),
"redirect_uris": [redirect_uri],
"scope": scope,
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "private_key_jwt",
"token_endpoint_auth_signing_alg": "ES256",
"application_type": "web",
"dpop_bound_access_tokens": true,
"jwks": { "keys": [atproto_oauth::jwk::generate(&client_key)?] },
});
let app = axum::Router::new()
.route("/x", get(|| async { "x marks the spot" }))
.route("/oauth-client-metadata.json", get(move || async move { Json(metadata) }));
devnet.serve(N_HOST, app).await?;
let response = devnet.http().get(format!("https://{N_HOST}/x")).send().await?;
assert_eq!(response.status(), 200);
assert_eq!(response.text().await?, "x marks the spot");
let unknown = devnet.http().get("https://unknown.zkwid.test/x").send().await;
assert!(unknown.is_err());
let client = OAuthClient { redirect_uri: redirect_uri.clone(), client_id, private_signing_key_data: client_key };
let login = devnet.oauth_login(&client, scope).await?;
assert!(login.redirect.starts_with(&redirect_uri), "{}", login.redirect);
assert!(login.redirect.contains("code="), "{}", login.redirect);
assert_eq!(login.tokens.sub.as_deref(), Some(devnet.user.did.as_str()));
assert!(login.tokens.scope.contains("repo:at.zkwid.demo.log"), "{}", login.tokens.scope);
Ok(())
}