summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbryan newbold <bnewbold@robocracy.org>2023-08-20 19:56:22 -0700
committerbryan newbold <bnewbold@robocracy.org>2023-08-20 19:56:22 -0700
commit23416af782a179a658711e958e977e19ae97067b (patch)
tree09e605dbd105c0628f6614e421c0dd43bb8ce3dc
parentcc1dea6ea34260201c1df09959c7c4566d16d918 (diff)
downloadadenosine-23416af782a179a658711e958e977e19ae97067b.tar.gz
adenosine-23416af782a179a658711e958e977e19ae97067b.zip
many updates from spring 2023 lex refactor
-rw-r--r--adenosine-cli/src/bin/adenosine.rs105
-rw-r--r--adenosine-cli/src/pretty.rs6
-rw-r--r--adenosine-pds/src/bin/adenosine-pds.rs1
-rw-r--r--adenosine-pds/src/db.rs3
-rw-r--r--adenosine-pds/src/db_bsky.rs117
-rw-r--r--adenosine-pds/src/lib.rs56
-rw-r--r--adenosine-pds/src/web.rs6
-rw-r--r--adenosine-pds/templates/macro.html2
-rw-r--r--adenosine/src/app_bsky/mod.rs169
-rw-r--r--adenosine/src/com_atproto/mod.rs6
-rw-r--r--adenosine/src/com_atproto/repo/mod.rs20
-rw-r--r--adenosine/src/xrpc.rs6
-rw-r--r--extra/adenosine.111
-rw-r--r--extra/adenosine.1.md8
-rw-r--r--extra/adenosine.1.scdoc7
15 files changed, 319 insertions, 204 deletions
diff --git a/adenosine-cli/src/bin/adenosine.rs b/adenosine-cli/src/bin/adenosine.rs
index 7f81191..6900b20 100644
--- a/adenosine-cli/src/bin/adenosine.rs
+++ b/adenosine-cli/src/bin/adenosine.rs
@@ -122,7 +122,6 @@ enum AccountCommand {
/// Deletes the current login session
Logout,
/// Fetches account metadata for the current session
- Info,
// TODO: CreateRevocationKey or CreateDid
CreateInvite {
#[structopt(short = "-u", default_value = "1")]
@@ -133,7 +132,7 @@ enum AccountCommand {
#[derive(StructOpt)]
enum RepoCommand {
/// Get the current 'root' commit for a DID
- Root {
+ Head {
/// Repository DID, or uses the current session account
did: Option<DidOrHost>,
},
@@ -371,15 +370,21 @@ fn run(opt: Opt) -> Result<()> {
.as_ref()
.map(|v| v.to_string())
.unwrap_or(require_auth_did(&opt, &mut xrpc_client)?.to_string());
- params.insert("user".to_string(), name);
- xrpc_client.get(&Nsid::from_str("com.atproto.repo.describe")?, Some(params))?
+ params.insert("repo".to_string(), name);
+ xrpc_client.get(
+ &Nsid::from_str("com.atproto.repo.describeRepo")?,
+ Some(params),
+ )?
}
Command::Resolve { name } => {
- params.insert("name".to_string(), name.to_string());
- xrpc_client.get(&Nsid::from_str("com.atproto.handle.resolve")?, Some(params))?
+ params.insert("handle".to_string(), name.to_string());
+ xrpc_client.get(
+ &Nsid::from_str("com.atproto.identity.resolveHandle")?,
+ Some(params),
+ )?
}
Command::Get { uri, cid } => {
- params.insert("user".to_string(), uri.repository.to_string());
+ params.insert("repo".to_string(), uri.repository.to_string());
params.insert(
"collection".to_string(),
uri.collection.ok_or(anyhow!("collection required"))?,
@@ -395,12 +400,15 @@ fn run(opt: Opt) -> Result<()> {
}
Command::Ls { uri } => {
// TODO: option to print fully-qualified path?
- params.insert("user".to_string(), uri.repository.to_string());
+ params.insert("repo".to_string(), uri.repository.to_string());
if uri.collection.is_none() {
// if a repository, but no collection, list the collections
let describe = xrpc_client
- .get(&Nsid::from_str("com.atproto.repo.describe")?, Some(params))?
- .ok_or(anyhow!("expected a repo.describe response"))?;
+ .get(
+ &Nsid::from_str("com.atproto.repo.describeRepo")?,
+ Some(params),
+ )?
+ .ok_or(anyhow!("expected a repo.describeRepo response"))?;
for c in describe["collections"]
.as_array()
.ok_or(anyhow!("expected collection list"))?
@@ -439,7 +447,7 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.createRecord")?,
None,
Some(json!({
- "did": did,
+ "repo": did,
"collection": collection,
// TODO: "validate" (boolean)
"record": val
@@ -457,7 +465,7 @@ fn run(opt: Opt) -> Result<()> {
.clone()
.ok_or(anyhow!("collection required"))?;
let rkey = uri.record.clone().ok_or(anyhow!("record key required"))?;
- params.insert("did".to_string(), did.clone());
+ params.insert("repo".to_string(), did.clone());
params.insert("collection".to_string(), collection.clone());
params.insert("rkey".to_string(), rkey.clone());
// fetch existing, extend map with fields, put the updated value
@@ -469,7 +477,7 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.putRecord")?,
None,
Some(json!({
- "did": did,
+ "repo": did,
"collection": collection,
"rkey": rkey,
"record": record,
@@ -488,7 +496,7 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.deleteRecord")?,
None,
Some(json!({
- "did": did,
+ "repo": did,
"collection": collection,
"rkey": rkey,
})),
@@ -531,7 +539,7 @@ fn run(opt: Opt) -> Result<()> {
body["inviteCode"] = json!(code);
}
xrpc_client.post(
- &Nsid::from_str("com.atproto.account.create")?,
+ &Nsid::from_str("com.atproto.server.createAccount")?,
None,
Some(body),
)?
@@ -539,7 +547,7 @@ fn run(opt: Opt) -> Result<()> {
Command::Account {
cmd: AccountCommand::Login { handle, password },
} => xrpc_client.post(
- &Nsid::from_str("com.atproto.session.create")?,
+ &Nsid::from_str("com.atproto.server.createSession")?,
None,
Some(json!({
"handle": handle,
@@ -548,25 +556,34 @@ fn run(opt: Opt) -> Result<()> {
)?,
Command::Account {
cmd: AccountCommand::Refresh,
- } => xrpc_client.post(&Nsid::from_str("com.atproto.session.refresh")?, None, None)?,
+ } => xrpc_client.post(
+ &Nsid::from_str("com.atproto.server.refreshSession")?,
+ None,
+ None,
+ )?,
Command::Account {
cmd: AccountCommand::Logout,
- } => xrpc_client.post(&Nsid::from_str("com.atproto.session.delete")?, None, None)?,
+ } => xrpc_client.post(
+ &Nsid::from_str("com.atproto.server.deleteSession")?,
+ None,
+ None,
+ )?,
Command::Account {
cmd: AccountCommand::Delete,
- } => xrpc_client.post(&Nsid::from_str("com.atproto.account.delete")?, None, None)?,
- Command::Account {
- cmd: AccountCommand::Info,
- } => xrpc_client.get(&Nsid::from_str("com.atproto.account.get")?, None)?,
+ } => xrpc_client.post(
+ &Nsid::from_str("com.atproto.server.deleteAccount")?,
+ None,
+ None,
+ )?,
Command::Account {
cmd: AccountCommand::CreateInvite { uses },
} => xrpc_client.post(
- &Nsid::from_str("com.atproto.account.createInviteCode")?,
+ &Nsid::from_str("com.atproto.server.createInviteCode")?,
None,
Some(json!({ "useCount": uses })),
)?,
Command::Repo {
- cmd: RepoCommand::Root { did },
+ cmd: RepoCommand::Head { did },
} => {
let did = match did {
Some(DidOrHost::Host(_)) => return Err(anyhow!("expected a DID, not a hostname")),
@@ -574,7 +591,7 @@ fn run(opt: Opt) -> Result<()> {
None => jwt_did.ok_or(anyhow!("expected a DID"))?,
};
params.insert("did".to_string(), did);
- xrpc_client.get(&Nsid::from_str("com.atproto.sync.getRoot")?, Some(params))?
+ xrpc_client.get(&Nsid::from_str("com.atproto.sync.getHead")?, Some(params))?
}
Command::Repo {
cmd: RepoCommand::Export { did, from },
@@ -617,7 +634,7 @@ fn run(opt: Opt) -> Result<()> {
.as_ref()
.map(|v| v.to_string())
.unwrap_or(require_auth_did(&opt, &mut xrpc_client)?.to_string());
- params.insert("author".to_string(), name);
+ params.insert("actor".to_string(), name);
let resp = xrpc_client.get(
&Nsid::from_str("app.bsky.feed.getAuthorFeed")?,
Some(params),
@@ -630,7 +647,7 @@ fn run(opt: Opt) -> Result<()> {
.iter()
{
let val: serde_json::Value = val.clone();
- let fi: app_bsky::FeedPostView = serde_json::from_value(val)?;
+ let fi: app_bsky::FeedViewPost = serde_json::from_value(val)?;
pretty::pp_feed_post_view(&fi)?;
}
None
@@ -652,7 +669,7 @@ fn run(opt: Opt) -> Result<()> {
{
let val: serde_json::Value = val.clone();
//print_result_json(Some(val.clone()))?;
- let fi: app_bsky::FeedPostView = serde_json::from_value(val)?;
+ let fi: app_bsky::FeedViewPost = serde_json::from_value(val)?;
pretty::pp_feed_post_view(&fi)?;
}
None
@@ -677,7 +694,7 @@ fn run(opt: Opt) -> Result<()> {
resp["thread"]
.as_object()
.ok_or(anyhow!("expected thread from getPostThread"))?;
- let tpv: app_bsky::ThreadPostView = serde_json::from_value(resp["thread"].clone())?;
+ let tpv: app_bsky::ThreadViewPost = serde_json::from_value(resp["thread"].clone())?;
pretty::pp_thread_post_view(&tpv)?;
None
} else {
@@ -688,7 +705,10 @@ fn run(opt: Opt) -> Result<()> {
cmd: BskyCommand::Notifications,
} => {
require_auth_did(&opt, &mut xrpc_client)?;
- xrpc_client.get(&Nsid::from_str("app.bsky.notification.list")?, None)?
+ xrpc_client.get(
+ &Nsid::from_str("app.bsky.notification.listNotifications")?,
+ None,
+ )?
}
Command::Bsky {
cmd: BskyCommand::Post { ref text },
@@ -698,7 +718,7 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.createRecord")?,
None,
Some(json!({
- "did": did,
+ "repo": did,
"collection": "app.bsky.feed.post",
"record": {
"text": text,
@@ -711,7 +731,7 @@ fn run(opt: Opt) -> Result<()> {
cmd: BskyCommand::Repost { ref uri },
} => {
let did = require_auth_did(&opt, &mut xrpc_client)?;
- params.insert("user".to_string(), uri.repository.to_string());
+ params.insert("repo".to_string(), uri.repository.to_string());
params.insert(
"collection".to_string(),
uri.collection
@@ -732,7 +752,7 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.createRecord")?,
None,
Some(json!({
- "did": did,
+ "repo": did,
"collection": "app.bsky.feed.repost",
"record": {
"subject": {
@@ -748,7 +768,7 @@ fn run(opt: Opt) -> Result<()> {
cmd: BskyCommand::Like { ref uri },
} => {
let did = require_auth_did(&opt, &mut xrpc_client)?;
- params.insert("user".to_string(), uri.repository.to_string());
+ params.insert("repo".to_string(), uri.repository.to_string());
params.insert(
"collection".to_string(),
uri.collection
@@ -769,11 +789,10 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.createRecord")?,
None,
Some(json!({
- "did": did,
- "collection": "app.bsky.feed.vote",
+ "repo": did,
+ "collection": "app.bsky.feed.like",
"record": {
"subject": { "uri": uri.to_string(), "cid": cid },
- "direction": "up",
"createdAt": created_at_now(),
},
})),
@@ -787,7 +806,7 @@ fn run(opt: Opt) -> Result<()> {
&Nsid::from_str("com.atproto.repo.createRecord")?,
None,
Some(json!({
- "did": did,
+ "repo": did,
"collection": "app.bsky.graph.follow",
"record": {
"subject": { "did": uri.to_string() },
@@ -807,10 +826,14 @@ fn run(opt: Opt) -> Result<()> {
xrpc_client.get(&Nsid::from_str("app.bsky.actor.getProfile")?, Some(params))?
}
Command::Bsky {
- cmd: BskyCommand::SearchUsers { query },
+ cmd: BskyCommand::SearchUsers { ref query },
} => {
- params.insert("term".to_string(), query);
- xrpc_client.get(&Nsid::from_str("app.bsky.actor.search")?, Some(params))?
+ require_auth_did(&opt, &mut xrpc_client)?;
+ params.insert("term".to_string(), query.to_string());
+ xrpc_client.get(
+ &Nsid::from_str("app.bsky.actor.searchActors")?,
+ Some(params),
+ )?
}
};
print_result_json(result)?;
diff --git a/adenosine-cli/src/pretty.rs b/adenosine-cli/src/pretty.rs
index 764a46f..a3cb5d6 100644
--- a/adenosine-cli/src/pretty.rs
+++ b/adenosine-cli/src/pretty.rs
@@ -1,9 +1,9 @@
-use adenosine::app_bsky::{FeedPostView, PostView, ThreadPostView};
+use adenosine::app_bsky::{FeedViewPost, PostView, ThreadViewPost};
use anyhow::Result;
use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
-pub fn pp_thread_post_view(tpv: &ThreadPostView) -> Result<()> {
+pub fn pp_thread_post_view(tpv: &ThreadViewPost) -> Result<()> {
// TODO: this could do better
if let Some(parent) = &tpv.parent {
pp_thread_post_view(parent)?;
@@ -31,7 +31,7 @@ pub fn pp_thread_post_view(tpv: &ThreadPostView) -> Result<()> {
Ok(())
}
-pub fn pp_feed_post_view(fpv: &FeedPostView) -> Result<()> {
+pub fn pp_feed_post_view(fpv: &FeedViewPost) -> Result<()> {
let mut stdout = StandardStream::stdout(ColorChoice::Always);
if let Some(repost) = &fpv.reason {
diff --git a/adenosine-pds/src/bin/adenosine-pds.rs b/adenosine-pds/src/bin/adenosine-pds.rs
index e92c131..5e8842c 100644
--- a/adenosine-pds/src/bin/adenosine-pds.rs
+++ b/adenosine-pds/src/bin/adenosine-pds.rs
@@ -211,6 +211,7 @@ fn main() -> Result<()> {
did_plc,
} => {
let req = com_atproto::AccountRequest {
+ did: None,
email,
handle: handle.clone(),
password,
diff --git a/adenosine-pds/src/db.rs b/adenosine-pds/src/db.rs
index 4cbece6..2dac721 100644
--- a/adenosine-pds/src/db.rs
+++ b/adenosine-pds/src/db.rs
@@ -124,6 +124,7 @@ impl AtpDatabase {
Ok(com_atproto::Session {
did: did.to_string(),
name: handle.to_string(),
+ email: None,
accessJwt: jwt.to_string(),
refreshJwt: jwt,
})
@@ -193,7 +194,7 @@ impl AtpDatabase {
// need to re-compute the CID from DagCbor re-encoding, I guess. bleh.
let block = Block::<DefaultParams>::encode(DagCborCodec, Code::Sha2_256, &val)?;
let cid = *block.cid();
- let post: app_bsky::Post = serde_json::from_value(ipld_into_json_value(val))?;
+ let post: app_bsky::PostRecord = serde_json::from_value(ipld_into_json_value(val))?;
let (reply_to_parent_uri, reply_to_root_uri) = match post.reply {
Some(ref reply) => (Some(reply.parent.uri.clone()), Some(reply.root.uri.clone())),
None => (None, None),
diff --git a/adenosine-pds/src/db_bsky.rs b/adenosine-pds/src/db_bsky.rs
index b80ff4f..c603235 100644
--- a/adenosine-pds/src/db_bsky.rs
+++ b/adenosine-pds/src/db_bsky.rs
@@ -8,7 +8,6 @@ use adenosine::repo::Mutation;
use anyhow::anyhow;
use libipld::Cid;
use rusqlite::params;
-use serde_json::json;
use std::str::FromStr;
/// Handles updating the database with creation, update, deletion of arbitrary records
@@ -59,7 +58,10 @@ pub fn bsky_mutate_db(db: &mut AtpDatabase, did: &Did, mutations: Vec<Mutation>)
}
// TODO: should probably return Result<Option<Profile>>?
-pub fn bsky_get_profile(srv: &mut AtpService, did: &Did) -> Result<app_bsky::ProfileView> {
+pub fn bsky_get_profile_detailed(
+ srv: &mut AtpService,
+ did: &Did,
+) -> Result<app_bsky::ProfileViewDetailed> {
// first get the profile record
let mut profile_cid: Option<Cid> = None;
let commit_cid = match srv.repo.lookup_commit(did)? {
@@ -78,7 +80,7 @@ pub fn bsky_get_profile(srv: &mut AtpService, did: &Did) -> Result<app_bsky::Pro
if let Some(cid) = profile_cid {
let record: app_bsky::ProfileRecord =
serde_json::from_value(ipld_into_json_value(srv.repo.get_ipld(&cid)?))?;
- (Some(record.displayName), record.description)
+ (record.displayName, record.description)
} else {
(None, None)
};
@@ -102,22 +104,33 @@ pub fn bsky_get_profile(srv: &mut AtpService, did: &Did) -> Result<app_bsky::Pro
.conn
.prepare_cached("SELECT COUNT(*) FROM bsky_follow WHERE subject_did = $1")?;
let followers_count: u64 = stmt.query_row(params!(did.to_string()), |row| row.get(0))?;
- let decl = app_bsky::DeclRef {
- actorType: "app.bsky.system.actorUser".to_string(),
- cid: "bafyreid27zk7lbis4zw5fz4podbvbs4fc5ivwji3dmrwa6zggnj4bnd57u".to_string(),
- };
- Ok(app_bsky::ProfileView {
+ Ok(app_bsky::ProfileViewDetailed {
did: did.to_string(),
handle,
- creator: did.to_string(),
displayName: display_name,
description,
- declaration: decl,
+ avatar: None,
+ banner: None,
followersCount: followers_count,
followsCount: follows_count,
postsCount: post_count,
- membersCount: 0,
- viewer: json!({}),
+ viewer: None,
+ labels: None,
+ indexedAt: None,
+ })
+}
+
+pub fn bsky_get_profile(srv: &mut AtpService, did: &Did) -> Result<app_bsky::ProfileView> {
+ let d = bsky_get_profile_detailed(srv, did)?;
+ Ok(app_bsky::ProfileView {
+ did: d.did,
+ handle: d.handle,
+ displayName: d.displayName,
+ description: d.description,
+ avatar: d.avatar,
+ indexedAt: d.indexedAt,
+ viewer: d.viewer,
+ labels: d.labels,
})
}
@@ -177,9 +190,10 @@ fn feed_row(row: &rusqlite::Row) -> Result<FeedRow> {
})
}
-fn feed_row_to_item(srv: &mut AtpService, row: FeedRow) -> Result<app_bsky::FeedPostView> {
+fn feed_row_to_item(srv: &mut AtpService, row: FeedRow) -> Result<app_bsky::FeedViewPost> {
let record_ipld = srv.repo.get_ipld(&row.item_post_cid)?;
- let post_record: app_bsky::Post = serde_json::from_value(ipld_into_json_value(record_ipld))?;
+ let post_record: app_bsky::PostRecord =
+ serde_json::from_value(ipld_into_json_value(record_ipld))?;
let uri = format!(
"at://{}/{}/{}",
row.item_did, "app.bsky.feed.post", row.item_post_tid
@@ -201,31 +215,27 @@ fn feed_row_to_item(srv: &mut AtpService, row: FeedRow) -> Result<app_bsky::Feed
.prepare_cached("SELECT COUNT(*) FROM bsky_post WHERE reply_to_parent_uri = $1")?;
let reply_count: u64 = stmt.query_row(params!(uri), |row| row.get(0))?;
- let decl = app_bsky::DeclRef {
- actorType: "app.bsky.system.actorUser".to_string(),
- cid: "bafyreid27zk7lbis4zw5fz4podbvbs4fc5ivwji3dmrwa6zggnj4bnd57u".to_string(),
- };
- let feed_item = app_bsky::FeedPostView {
+ let feed_item = app_bsky::FeedViewPost {
post: app_bsky::PostView {
uri,
cid: row.item_post_cid.to_string(),
- author: app_bsky::UserView {
+ author: app_bsky::ProfileViewBasic {
did: row.item_did.to_string(),
handle: row.item_handle,
- declaration: decl,
// TODO:
displayName: None,
avatar: None,
viewer: None,
+ labels: None,
},
record: post_record,
embed: None,
replyCount: reply_count,
repostCount: repost_count,
- upvoteCount: like_count,
- downvoteCount: 0,
+ likeCount: like_count,
indexedAt: row.indexed_at,
viewer: None,
+ labels: None,
},
// TODO:
reason: None,
@@ -235,7 +245,7 @@ fn feed_row_to_item(srv: &mut AtpService, row: FeedRow) -> Result<app_bsky::Feed
}
pub fn bsky_get_timeline(srv: &mut AtpService, did: &Did) -> Result<app_bsky::GenericFeed> {
- let mut feed: Vec<app_bsky::FeedPostView> = vec![];
+ let mut feed: Vec<app_bsky::FeedViewPost> = vec![];
// TODO: also handle reposts
let rows = {
let mut stmt = srv.atp_db
@@ -252,11 +262,11 @@ pub fn bsky_get_timeline(srv: &mut AtpService, did: &Did) -> Result<app_bsky::Ge
for row in rows {
feed.push(feed_row_to_item(srv, row)?);
}
- Ok(app_bsky::GenericFeed { feed })
+ Ok(app_bsky::GenericFeed { feed, cursor: None })
}
pub fn bsky_get_author_feed(srv: &mut AtpService, did: &Did) -> Result<app_bsky::GenericFeed> {
- let mut feed: Vec<app_bsky::FeedPostView> = vec![];
+ let mut feed: Vec<app_bsky::FeedViewPost> = vec![];
// TODO: also handle reposts
let rows = {
let mut stmt = srv.atp_db
@@ -273,7 +283,7 @@ pub fn bsky_get_author_feed(srv: &mut AtpService, did: &Did) -> Result<app_bsky:
for row in rows {
feed.push(feed_row_to_item(srv, row)?);
}
- Ok(app_bsky::GenericFeed { feed })
+ Ok(app_bsky::GenericFeed { feed, cursor: None })
}
// TODO: this is a partial implementation
@@ -298,7 +308,7 @@ pub fn bsky_get_thread(
_ => Err(anyhow!("expected a record in uri: {}", uri))?,
};
- // post itself, as a app_bsky::FeedPostView
+ // post itself, as a app_bsky::FeedViewPost
let post_items = {
let mut stmt = srv.atp_db
.conn
@@ -335,7 +345,7 @@ pub fn bsky_get_thread(
};
for row in rows {
let item = feed_row_to_item(srv, row)?.post;
- children.push(app_bsky::ThreadPostView {
+ children.push(app_bsky::ThreadViewPost {
post: Some(app_bsky::PostView {
uri: item.uri,
cid: item.cid,
@@ -343,11 +353,11 @@ pub fn bsky_get_thread(
record: item.record,
embed: item.embed,
replyCount: item.replyCount,
- upvoteCount: item.upvoteCount,
- downvoteCount: 0,
+ likeCount: item.likeCount,
repostCount: item.repostCount,
indexedAt: item.indexedAt,
viewer: None,
+ labels: None,
}),
// don't want a loop here
parent: None,
@@ -356,11 +366,14 @@ pub fn bsky_get_thread(
// for "notfound"
uri: None,
notFound: None,
+ // for "blocked" variant
+ blocked: None,
+ author: None,
});
}
let pip = post_item.post;
- let post = app_bsky::ThreadPostView {
+ let post = app_bsky::ThreadViewPost {
post: Some(app_bsky::PostView {
uri: pip.uri,
cid: pip.cid,
@@ -368,17 +381,20 @@ pub fn bsky_get_thread(
record: pip.record,
embed: pip.embed,
replyCount: pip.replyCount,
- upvoteCount: pip.upvoteCount,
- downvoteCount: 0,
+ likeCount: pip.likeCount,
repostCount: pip.repostCount,
indexedAt: pip.indexedAt,
viewer: None,
+ labels: None,
}),
parent,
replies: Some(children),
// for "notfound" variant
uri: None,
notFound: None,
+ // for "blocked" variant
+ blocked: None,
+ author: None,
};
Ok(app_bsky::PostThread { thread: post })
}
@@ -394,6 +410,7 @@ fn test_bsky_profile() {
let mut srv = AtpService::new_ephemeral().unwrap();
let req = com_atproto::AccountRequest {
+ did: None,
email: "test@bogus.com".to_string(),
handle: "handle.test".to_string(),
password: "bogus".to_string(),
@@ -402,7 +419,7 @@ fn test_bsky_profile() {
};
let session = create_account(&mut srv, &req, true).unwrap();
let did = Did::from_str(&session.did).unwrap();
- let profile = bsky_get_profile(&mut srv, &did).unwrap();
+ let profile = bsky_get_profile_detailed(&mut srv, &did).unwrap();
assert_eq!(profile.did, session.did);
assert_eq!(profile.handle, req.handle);
assert_eq!(profile.displayName, None);
@@ -412,21 +429,25 @@ fn test_bsky_profile() {
assert_eq!(profile.postsCount, 0);
let record = app_bsky::ProfileRecord {
- displayName: "Test Name".to_string(),
+ displayName: Some("Test Name".to_string()),
description: Some("short description".to_string()),
+ avatar: None,
+ banner: None,
};
bsky_update_profile(&mut srv, &did, record.clone()).unwrap();
let profile = bsky_get_profile(&mut srv, &did).unwrap();
- assert_eq!(profile.displayName, Some(record.displayName));
+ assert_eq!(profile.displayName, record.displayName);
assert_eq!(profile.description, record.description);
let record = app_bsky::ProfileRecord {
- displayName: "New Test Name".to_string(),
+ displayName: Some("New Test Name".to_string()),
description: Some("longer description".to_string()),
+ avatar: None,
+ banner: None,
};
bsky_update_profile(&mut srv, &did, record.clone()).unwrap();
let profile = bsky_get_profile(&mut srv, &did).unwrap();
- assert_eq!(profile.displayName, Some(record.displayName));
+ assert_eq!(profile.displayName, record.displayName);
assert_eq!(profile.description, record.description);
let mutations = vec![
@@ -461,7 +482,7 @@ fn test_bsky_profile() {
.unwrap();
bsky_mutate_db(&mut srv.atp_db, &did, mutations).unwrap();
- let profile = bsky_get_profile(&mut srv, &did).unwrap();
+ let profile = bsky_get_profile_detailed(&mut srv, &did).unwrap();
assert_eq!(profile.followersCount, 1);
assert_eq!(profile.followsCount, 2);
assert_eq!(profile.postsCount, 3);
@@ -482,6 +503,7 @@ fn test_bsky_feeds() {
let mut srv = AtpService::new_ephemeral().unwrap();
let alice_did = {
let req = com_atproto::AccountRequest {
+ did: None,
email: "alice@bogus.com".to_string(),
handle: "alice.test".to_string(),
password: "bogus".to_string(),
@@ -493,6 +515,7 @@ fn test_bsky_feeds() {
};
let bob_did = {
let req = com_atproto::AccountRequest {
+ did: None,
email: "bob@bogus.com".to_string(),
handle: "bob.test".to_string(),
password: "bogus".to_string(),
@@ -504,6 +527,7 @@ fn test_bsky_feeds() {
};
let carol_did = {
let req = com_atproto::AccountRequest {
+ did: None,
email: "carol@bogus.com".to_string(),
handle: "carol.test".to_string(),
password: "bogus".to_string(),
@@ -596,7 +620,7 @@ fn test_bsky_feeds() {
bsky_mutate_db(&mut srv.atp_db, &carol_did, mutations).unwrap();
// test alice profile: counts should be updated
- let alice_profile = bsky_get_profile(&mut srv, &alice_did).unwrap();
+ let alice_profile = bsky_get_profile_detailed(&mut srv, &alice_did).unwrap();
assert_eq!(alice_profile.followersCount, 1);
assert_eq!(alice_profile.followsCount, 0);
assert_eq!(alice_profile.postsCount, 3);
@@ -621,18 +645,17 @@ fn test_bsky_feeds() {
assert_eq!(alice_feed.feed[2].post.embed, None);
assert_eq!(alice_feed.feed[2].post.replyCount, 0);
assert_eq!(alice_feed.feed[2].post.repostCount, 0);
- assert_eq!(alice_feed.feed[2].post.upvoteCount, 1);
- assert_eq!(alice_feed.feed[2].post.downvoteCount, 0);
+ assert_eq!(alice_feed.feed[2].post.likeCount, 1);
assert_eq!(alice_feed.feed[1].post.author.did, alice_did.to_string());
assert_eq!(alice_feed.feed[1].post.replyCount, 0);
assert_eq!(alice_feed.feed[1].post.repostCount, 1);
- assert_eq!(alice_feed.feed[1].post.upvoteCount, 0);
+ assert_eq!(alice_feed.feed[1].post.likeCount, 0);
assert_eq!(alice_feed.feed[0].post.author.did, alice_did.to_string());
assert_eq!(alice_feed.feed[0].post.replyCount, 1);
assert_eq!(alice_feed.feed[0].post.repostCount, 0);
- assert_eq!(alice_feed.feed[0].post.upvoteCount, 0);
+ assert_eq!(alice_feed.feed[0].post.likeCount, 0);
// test bob timeline: should include alice posts
let bob_timeline = bsky_get_timeline(&mut srv, &bob_did).unwrap();
@@ -687,6 +710,7 @@ fn test_bsky_thread() {
let mut srv = AtpService::new_ephemeral().unwrap();
let alice_did = {
let req = com_atproto::AccountRequest {
+ did: None,
email: "alice@bogus.com".to_string(),
handle: "alice.test".to_string(),
password: "bogus".to_string(),
@@ -698,6 +722,7 @@ fn test_bsky_thread() {
};
let bob_did = {
let req = com_atproto::AccountRequest {
+ did: None,
email: "bob@bogus.com".to_string(),
handle: "bob.test".to_string(),
password: "bogus".to_string(),
@@ -758,7 +783,7 @@ fn test_bsky_thread() {
assert_eq!(ppost.embed, None);
assert_eq!(ppost.replyCount, 1);
assert_eq!(ppost.repostCount, 0);
- assert_eq!(ppost.upvoteCount, 0);
+ assert_eq!(ppost.likeCount, 0);
assert_eq!(post.replies.as_ref().unwrap().len(), 1);
let post_replies = post.replies.unwrap();
diff --git a/adenosine-pds/src/lib.rs b/adenosine-pds/src/lib.rs
index c267135..cb41cb9 100644
--- a/adenosine-pds/src/lib.rs
+++ b/adenosine-pds/src/lib.rs
@@ -303,7 +303,7 @@ fn xrpc_get_handler(
)
}
"com.atproto.repo.getRecord" => {
- let did = Did::from_str(&xrpc_required_param(request, "user")?)?;
+ let did = Did::from_str(&xrpc_required_param(request, "repo")?)?;
let collection = Nsid::from_str(&xrpc_required_param(request, "collection")?)?;
let rkey = Tid::from_str(&xrpc_required_param(request, "rkey")?)?;
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
@@ -317,8 +317,8 @@ fn xrpc_get_handler(
Err(e) => Err(e),
}
}
- "com.atproto.sync.getRoot" => {
- let did = Did::from_str(&xrpc_required_param(request, "did")?)?;
+ "com.atproto.sync.getHead" => {
+ let did = Did::from_str(&xrpc_required_param(request, "repo")?)?;
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
srv.repo
.lookup_commit(&did)?
@@ -329,7 +329,7 @@ fn xrpc_get_handler(
// TODO: limit, before, after, tid, reverse
// TODO: handle non-DID 'user'
// TODO: limit result set size
- let did = Did::from_str(&xrpc_required_param(request, "user")?)?;
+ let did = Did::from_str(&xrpc_required_param(request, "repo")?)?;
let collection = Nsid::from_str(&xrpc_required_param(request, "collection")?)?;
let mut record_list: Vec<Value> = vec![];
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
@@ -350,15 +350,6 @@ fn xrpc_get_handler(
}
Ok(json!({ "records": record_list }))
}
- "com.atproto.session.get" => {
- let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
- let auth_did = &xrpc_check_auth_header(&mut srv, request, None)?;
- let handle = srv
- .atp_db
- .resolve_did(auth_did)?
- .expect("registered account has handle");
- Ok(json!({"did": auth_did.to_string(), "handle": handle}))
- }
"com.atproto.handle.resolve" => {
let handle = xrpc_required_param(request, "handle")?;
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
@@ -370,17 +361,17 @@ fn xrpc_get_handler(
}
}
"com.atproto.repo.describe" => {
- let did = Did::from_str(&xrpc_required_param(request, "user")?)?;
+ let did = Did::from_str(&xrpc_required_param(request, "repo")?)?;
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
let did_doc = srv.atp_db.get_did_doc(&did)?;
let collections: Vec<String> = srv.repo.collections(&did)?;
let desc = com_atproto::repo::Describe {
- name: did.to_string(), // TODO: handle?
+ handle: did.to_string(), // TODO: handle?
did: did.to_string(),
didDoc: did_doc,
collections,
- nameIsCorrect: true,
+ handleIsCorrect: true,
};
Ok(json!(desc))
}
@@ -408,7 +399,7 @@ fn xrpc_get_handler(
}
"app.bsky.feed.getAuthorFeed" => {
// TODO did or handle
- let did = Did::from_str(&xrpc_required_param(request, "author")?)?;
+ let did = Did::from_str(&xrpc_required_param(request, "actor")?)?;
let mut srv = srv.lock().unwrap();
Ok(json!(bsky_get_author_feed(&mut srv, &did)?))
}
@@ -434,7 +425,7 @@ fn xrpc_get_handler(
let _auth_did = &xrpc_check_auth_header(&mut srv, request, None)?;
Ok(json!({"count": 0}))
}
- "app.bsky.notification.list" => {
+ "app.bsky.notification.listNotifications" => {
// TODO: actual implementation
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
let _auth_did = &xrpc_check_auth_header(&mut srv, request, None)?;
@@ -447,7 +438,7 @@ fn xrpc_get_handler(
}
fn xrpc_get_repo_handler(srv: &Mutex<AtpService>, request: &Request) -> Result<Vec<u8>> {
- let did = Did::from_str(&xrpc_required_param(request, "did")?)?;
+ let did = Did::from_str(&xrpc_required_param(request, "repo")?)?;
let mut srv = srv.lock().or(Err(XrpcError::MutexPoisoned))?;
// TODO: don't unwrap here
let commit_cid = srv.repo.lookup_commit(&did)?.unwrap();
@@ -520,7 +511,7 @@ fn xrpc_post_handler(
request: &Request,
) -> Result<serde_json::Value> {
match method {
- "com.atproto.account.create" => {
+ "com.atproto.server.createAccount" => {
// validate account request
let req: com_atproto::AccountRequest = rouille::input::json_input(request)
.map_err(|e| XrpcError::BadRequest(format!("failed to parse JSON body: {e}")))?;
@@ -546,18 +537,18 @@ fn xrpc_post_handler(
let sess = create_account(&mut srv, &req, true)?;
Ok(json!(sess))
}
- "com.atproto.session.create" => {
+ "com.atproto.server.createSession" => {
let req: com_atproto::SessionRequest = rouille::input::json_input(request)
.map_err(|e| XrpcError::BadRequest(format!("failed to parse JSON body: {e}")))?;
let mut srv = srv.lock().unwrap();
let keypair = srv.pds_keypair.clone();
Ok(json!(srv.atp_db.create_session(
- &req.handle,
+ &req.identifier,
&req.password,
&keypair
)?))
}
- "com.atproto.session.refresh" => {
+ "com.atproto.server.refreshSession" => {
// actually just returns current session, because we don't implement refresh
let mut srv = srv.lock().unwrap();
let did = xrpc_check_auth_header(&mut srv, request, None)?;
@@ -576,11 +567,12 @@ fn xrpc_post_handler(
Ok(json!(com_atproto::Session {
did: did.to_string(),
name: handle,
+ email: None,
accessJwt: jwt.to_string(),
refreshJwt: jwt.to_string(),
}))
}
- "com.atproto.session.delete" => {
+ "com.atproto.server.deleteSession" => {
let mut srv = srv.lock().unwrap();
let _did = xrpc_check_auth_header(&mut srv, request, None)?;
let header = request
@@ -597,10 +589,10 @@ fn xrpc_post_handler(
};
Ok(json!({}))
}
- "com.atproto.repo.batchWrite" => {
+ "com.atproto.repo.applyWrites" => {
let batch: com_atproto::repo::BatchWriteBody = rouille::input::json_input(request)?;
// TODO: validate edits against schemas
- let did = Did::from_str(&batch.did)?;
+ let did = Did::from_str(&batch.repo)?;
let mut srv = srv.lock().unwrap();
let _auth_did = &xrpc_check_auth_header(&mut srv, request, Some(&did))?;
let mut mutations: Vec<Mutation> = Default::default();
@@ -613,12 +605,12 @@ fn xrpc_post_handler(
.as_ref()
.map(|t| Tid::from_str(t).unwrap())
.unwrap_or_else(|| srv.tid_gen.next_tid()),
- json_value_into_ipld(w.value.clone()),
+ json_value_into_ipld(w.value.clone().unwrap()),
),
"update" => Mutation::Update(
Nsid::from_str(&w.collection)?,
Tid::from_str(w.rkey.as_ref().unwrap())?,
- json_value_into_ipld(w.value.clone()),
+ json_value_into_ipld(w.value.clone().unwrap()),
),
"delete" => Mutation::Delete(
Nsid::from_str(&w.collection)?,
@@ -685,7 +677,7 @@ fn xrpc_post_handler(
}
"com.atproto.sync.updateRepo" => {
// TODO: all other XRPC POST methods removed params (eg, 'did' in this case)
- let did = Did::from_str(&xrpc_required_param(request, "did")?)?;
+ let did = Did::from_str(&xrpc_required_param(request, "repo")?)?;
// important that this read is before we take the mutex, because it could be slow!
let mut car_bytes: Vec<u8> = Default::default();
// TODO: unwrap()
@@ -769,7 +761,7 @@ fn account_view_handler(
Ok(AccountView {
domain: host.to_string(),
did: did.clone(),
- profile: bsky_get_profile(&mut srv, &did)?,
+ profile: bsky_get_profile_detailed(&mut srv, &did)?,
feed: bsky_get_author_feed(&mut srv, &did)?.feed,
}
.render()?)
@@ -809,11 +801,11 @@ fn repo_view_handler(srv: &Mutex<AtpService>, did: &str, request: &Request) -> R
let commit = srv.repo.get_commit(commit_cid)?;
let collections: Vec<String> = srv.repo.collections(&did)?;
let desc = com_atproto::repo::Describe {
- name: did.to_string(), // TODO
+ handle: did.to_string(), // TODO
did: did.to_string(),
didDoc: did_doc,
collections,
- nameIsCorrect: true,
+ handleIsCorrect: true,
};
Ok(RepoView {
diff --git a/adenosine-pds/src/web.rs b/adenosine-pds/src/web.rs
index fc75a93..80e6f15 100644
--- a/adenosine-pds/src/web.rs
+++ b/adenosine-pds/src/web.rs
@@ -29,8 +29,8 @@ pub struct AboutView {
pub struct AccountView {
pub domain: String,
pub did: Did,
- pub profile: app_bsky::ProfileView,
- pub feed: Vec<app_bsky::FeedPostView>,
+ pub profile: app_bsky::ProfileViewDetailed,
+ pub feed: Vec<app_bsky::FeedViewPost>,
}
#[derive(Template)]
@@ -40,7 +40,7 @@ pub struct ThreadView {
pub did: Did,
pub collection: Nsid,
pub tid: Tid,
- pub post: app_bsky::ThreadPostView,
+ pub post: app_bsky::ThreadViewPost,
}
#[derive(Template)]
diff --git a/adenosine-pds/templates/macro.html b/adenosine-pds/templates/macro.html
index 795400b..d586adb 100644
--- a/adenosine-pds/templates/macro.html
+++ b/adenosine-pds/templates/macro.html
@@ -28,7 +28,7 @@
{{ item.record.text }}
<br>
<span class="counts">
- [<a href="#">{{ item.upvoteCount }} upvote</a> / <a href="#">{{ item.repostCount }} repost</a> / <a href="#">{{ item.replyCount }} reply</a>]
+ [<a href="#">{{ item.likeCount }} like</a> / <a href="#">{{ item.repostCount }} repost</a> / <a href="#">{{ item.replyCount }} reply</a>]
<a href="{{ item.uri|aturi_to_path }}" class="pink">[inspect]</a>
</span>
diff --git a/adenosine/src/app_bsky/mod.rs b/adenosine/src/app_bsky/mod.rs
index 76352f5..61063fb 100644
--- a/adenosine/src/app_bsky/mod.rs
+++ b/adenosine/src/app_bsky/mod.rs
@@ -26,7 +26,6 @@ pub struct RefRecord {
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct FollowSubject {
pub did: String,
- // pub declarationCid: String,
}
#[allow(non_snake_case)]
@@ -39,128 +38,158 @@ pub struct FollowRecord {
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct ProfileRecord {
- pub displayName: String,
+ pub displayName: Option<String>,
pub description: Option<String>,
+ pub avatar: Option<Blob>,
+ pub banner: Option<Blob>,
+ // TODO: self-labels
}
-// app.bsky.system.actorUser or app.bsky.system.actorScene
-#[allow(non_snake_case)]
-#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct Declaration {
- pub actorType: String,
-}
-
-// actorType: app.bsky.system.actorUser
-// cid: bafyreid27zk7lbis4zw5fz4podbvbs4fc5ivwji3dmrwa6zggnj4bnd57u
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct DeclRef {
- pub actorType: String,
- pub cid: String,
+pub struct Label {
+ pub src: String,
+ pub uri: String,
+ pub cid: Option<String>,
+ pub val: String,
+ pub neg: Option<bool>,
+ pub cts: String,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct ProfileView {
pub did: String,
- pub declaration: DeclRef,
pub handle: String,
- // for simple accounts, 'creator' is just the did
- pub creator: String,
pub displayName: Option<String>,
pub description: Option<String>,
- pub followersCount: u64,
- pub followsCount: u64,
- pub membersCount: u64,
- pub postsCount: u64,
- pub viewer: serde_json::Value,
+ pub avatar: Option<String>,
+ pub indexedAt: Option<String>,
+ pub viewer: Option<ViewerState>,
+ pub labels: Option<Vec<Label>>,
}
-/// for Timeline or AuthorFeed
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct GenericFeed {
- pub feed: Vec<FeedPostView>,
+pub struct ViewerState {
+ pub muted: Option<bool>,
+ pub mutedByList: Option<Value>, // TODO
+ pub blockedBy: Option<bool>,
+ pub blocking: Option<String>,
+ pub following: Option<String>,
+ pub followedBy: Option<String>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct User {
+pub struct ProfileViewBasic {
pub did: String,
pub handle: String,
pub displayName: Option<String>,
+ pub avatar: Option<String>,
+ pub viewer: Option<Value>,
+ pub labels: Option<Vec<Label>>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct UserView {
+pub struct ProfileViewDetailed {
pub did: String,
pub handle: String,
- pub declaration: DeclRef,
pub displayName: Option<String>,
+ pub description: Option<String>,
pub avatar: Option<String>,
- pub viewer: Option<Value>,
+ pub banner: Option<String>,
+ pub followersCount: u64,
+ pub followsCount: u64,
+ pub postsCount: u64,
+ pub indexedAt: Option<String>,
+ pub viewer: Option<ViewerState>,
+ pub labels: Option<Vec<Label>>,
}
+/// for Timeline or AuthorFeed
+#[allow(non_snake_case)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
+pub struct GenericFeed {
+ pub cursor: Option<String>,
+ pub feed: Vec<FeedViewPost>,
+}
+/* XXX:
+#[allow(non_snake_case)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
+pub struct User {
+ pub did: String,
+ pub handle: String,
+ pub displayName: Option<String>,
+}
+*/
+
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct PostView {
pub uri: String,
pub cid: String,
- pub author: UserView,
- pub record: Post,
+ pub author: ProfileViewBasic,
+ pub record: PostRecord,
pub embed: Option<PostEmbedView>,
pub replyCount: u64,
pub repostCount: u64,
- pub upvoteCount: u64,
- pub downvoteCount: u64,
+ pub likeCount: u64,
pub indexedAt: String,
pub viewer: Option<Value>,
+ pub labels: Option<Vec<Label>>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct ThreadPostView {
+pub struct ThreadViewPost {
// TODO: doing this as the intersetion of #threadViewPost and #notFoundPost. actually it is
// supposed to be a union type
// #notFoundPost fields (uri and notFound actually required)
pub uri: Option<String>,
pub notFound: Option<bool>,
+ // #blockedPost fields (uri and blocked actually required)
+ pub blocked: Option<bool>,
+ pub author: Option<Value>,
// #threadViewPost fields (post actually required)
pub post: Option<PostView>,
- pub parent: Option<Box<ThreadPostView>>,
- pub replies: Option<Vec<ThreadPostView>>,
+ pub parent: Option<Box<ThreadViewPost>>,
+ pub replies: Option<Vec<ThreadViewPost>>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct FeedPostView {
+pub struct FeedViewPost {
pub post: PostView,
- pub reply: Option<PostReply>,
+ pub reply: Option<ReplyRef>,
// TODO: this could extend to other "reasons" in the future
- pub reason: Option<RepostReason>,
+ pub reason: Option<ReasonRepost>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct RepostReason {
- pub by: UserView,
+pub struct ReasonRepost {
+ pub by: ProfileViewBasic,
pub indexedAt: String,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct Post {
+pub struct PostRecord {
pub text: String,
- pub reply: Option<PostReply>,
pub entities: Option<Vec<PostEntity>>,
+ pub facets: Option<Vec<RichtextFacet>>,
+ pub reply: Option<ReplyRef>,
pub embed: Option<PostEmbed>,
+ pub langs: Option<Vec<String>>,
+ pub labels: Option<Vec<String>>,
pub createdAt: Option<String>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct PostReply {
+pub struct ReplyRef {
// TODO: these should be StrongRef
pub parent: Subject,
pub root: Subject,
@@ -168,6 +197,28 @@ pub struct PostReply {
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
+pub struct RichtextFacet {
+ pub index: ByteSlice,
+ pub features: Vec<FacetFeature>,
+}
+
+#[allow(non_snake_case)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
+pub struct FacetFeature {
+ // TODO: this is a hack; actually separate mention and link types
+ pub did: Option<String>,
+ pub uri: Option<String>,
+}
+
+#[allow(non_snake_case)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
+pub struct ByteSlice {
+ pub byteStart: u64,
+ pub byteEnd: u64,
+}
+
+#[allow(non_snake_case)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct PostEntity {
pub index: TextSlice,
pub r#type: String,
@@ -186,13 +237,17 @@ pub struct TextSlice {
pub struct PostEmbed {
pub external: Option<EmbedExternal>,
pub images: Option<Vec<EmbedImage>>,
+ pub record: Option<StrongRef>,
+ pub recordWithMedia: Option<Value>, // TODO
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct PostEmbedView {
- pub external: Option<EmbedExternalView>,
pub images: Option<Vec<EmbedImageView>>,
+ pub external: Option<EmbedExternalView>,
+ pub record: Option<Value>, // TODO
+ pub recordWithMedia: Option<Value>, // TODO
}
#[allow(non_snake_case)]
@@ -223,8 +278,20 @@ pub struct EmbedImage {
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct Blob {
- pub cid: String,
+ #[serde(rename = "$type")]
+ pub blob_type: Option<String>,
+ #[serde(rename = "ref")]
+ pub link: Option<CidLink>,
+ pub cid: Option<String>, // deprecated
pub mimeType: String,
+ pub size: Option<u64>,
+}
+
+#[allow(non_snake_case)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
+pub struct CidLink {
+ #[serde(rename = "$link")]
+ pub cid: String,
}
#[allow(non_snake_case)]
@@ -238,9 +305,10 @@ pub struct EmbedImageView {
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct PostThread {
- pub thread: ThreadPostView,
+ pub thread: ThreadViewPost,
}
+/* XXX
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct FollowTarget {
@@ -252,11 +320,12 @@ pub struct FollowTarget {
pub createdAt: Option<String>,
pub indexedAt: String,
}
+*/
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
-pub struct Follow {
- // TODO: nested follow list?
+pub struct FollowList {
pub subject: Subject,
- pub follows: FollowTarget,
+ pub cursor: Option<String>,
+ pub follows: Vec<ProfileView>,
}
diff --git a/adenosine/src/com_atproto/mod.rs b/adenosine/src/com_atproto/mod.rs
index 8e2317a..7a6cbc0 100644
--- a/adenosine/src/com_atproto/mod.rs
+++ b/adenosine/src/com_atproto/mod.rs
@@ -7,15 +7,16 @@ pub mod repo;
pub struct AccountRequest {
pub email: String,
pub handle: String,
- pub password: String,
+ pub did: Option<String>,
pub inviteCode: Option<String>,
+ pub password: String,
pub recoveryKey: Option<String>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Deserialize, serde::Serialize, PartialEq, Eq)]
pub struct SessionRequest {
- pub handle: String,
+ pub identifier: String,
pub password: String,
}
@@ -24,6 +25,7 @@ pub struct SessionRequest {
pub struct Session {
pub did: String,
pub name: String,
+ pub email: Option<String>,
pub accessJwt: String,
pub refreshJwt: String,
}
diff --git a/adenosine/src/com_atproto/repo/mod.rs b/adenosine/src/com_atproto/repo/mod.rs
index aa66e98..de5b56b 100644
--- a/adenosine/src/com_atproto/repo/mod.rs
+++ b/adenosine/src/com_atproto/repo/mod.rs
@@ -3,11 +3,11 @@
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct Describe {
- pub name: String,
+ pub handle: String,
pub did: String,
pub didDoc: serde_json::Value,
pub collections: Vec<String>,
- pub nameIsCorrect: bool,
+ pub handleIsCorrect: bool,
}
#[allow(non_snake_case)]
@@ -15,7 +15,10 @@ pub struct Describe {
pub struct CreateRecord {
pub did: String,
pub collection: String,
+ pub rkey: Option<String>,
+ pub validate: Option<bool>,
pub record: serde_json::Value,
+ pub swapCommit: Option<String>,
}
#[allow(non_snake_case)]
@@ -24,7 +27,10 @@ pub struct PutRecord {
pub did: String,
pub collection: String,
pub rkey: String,
+ pub validate: Option<bool>,
pub record: serde_json::Value,
+ pub swapRecord: Option<String>,
+ pub swapCommit: Option<String>,
}
#[allow(non_snake_case)]
@@ -33,21 +39,25 @@ pub struct DeleteRecord {
pub did: String,
pub collection: String,
pub rkey: String,
+ pub swapRecord: Option<String>,
+ pub swapCommit: Option<String>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct BatchWriteBody {
- pub did: String,
+ pub repo: String,
+ pub validate: Option<bool>,
pub writes: Vec<BatchWrite>,
+ pub swapCommit: Option<String>,
}
#[allow(non_snake_case)]
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Eq)]
pub struct BatchWrite {
- #[serde(rename = "type")]
+ #[serde(rename = "$type")]
pub op_type: String,
pub collection: String,
pub rkey: Option<String>,
- pub value: serde_json::Value,
+ pub value: Option<serde_json::Value>,
}
diff --git a/adenosine/src/xrpc.rs b/adenosine/src/xrpc.rs
index 6a89ba1..2a185ce 100644
--- a/adenosine/src/xrpc.rs
+++ b/adenosine/src/xrpc.rs
@@ -106,7 +106,11 @@ impl XrpcClient {
/// Uses refresh token to update auth token
pub fn auth_refresh(&mut self) -> Result<()> {
self.auth_token = self.refresh_token.clone();
- let resp = self.post(&Nsid::from_str("com.atproto.session.refresh")?, None, None)?;
+ let resp = self.post(
+ &Nsid::from_str("com.atproto.server.refreshSession")?,
+ None,
+ None,
+ )?;
let resp = resp.ok_or(anyhow!("missing session auth info"))?;
self.auth_token = resp["accessJwt"].as_str().map(|s| s.to_string());
self.refresh_token = resp["refreshJwt"].as_str().map(|s| s.to_string());
diff --git a/extra/adenosine.1 b/extra/adenosine.1
index 060977e..658bca8 100644
--- a/extra/adenosine.1
+++ b/extra/adenosine.1
@@ -5,7 +5,7 @@
.nh
.ad l
.\" Begin generated content:
-.TH "adenosine" "1" "2023-03-05" "adenosine CLI Client Manual Page"
+.TH "adenosine" "1" "2023-08-21" "adenosine CLI Client Manual Page"
.P
.SH NAME
.P
@@ -150,11 +150,6 @@ Query by partial handle
.P
\fBaccount register --email <email> --password <password> --handle <handle>\fR
.P
-\fBaccount info\fR
-.RS 4
-Fetches account metadata for the current session
-.P
-.RE
\fBaccount login --password <password> --handle <handle>\fR
.RS 4
Create a new authenticated session
@@ -177,9 +172,9 @@ Dump raw binary repository as CAR format to stdout
Read raw binary repository as CAR format from stdin, and import to PDS
.P
.RE
-\fBrepo root [did]\fR
+\fBrepo head [did]\fR
.RS 4
-Get the current '\&root'\& commit for a DID
+Get the latest commit for a DID
.P
.RE
.SH OPTIONS
diff --git a/extra/adenosine.1.md b/extra/adenosine.1.md
index a724f3c..7f70eb3 100644
--- a/extra/adenosine.1.md
+++ b/extra/adenosine.1.md
@@ -129,10 +129,6 @@ parameters and body fields. Body fields only used for \"post\" requests.
**account register \--email \<email\> \--password \<password\> \--handle
\<handle\>**
-**account info**
-
-> Fetches account metadata for the current session
-
**account login \--password \<password\> \--handle \<handle\>**
> Create a new authenticated session
@@ -151,9 +147,9 @@ parameters and body fields. Body fields only used for \"post\" requests.
> Read raw binary repository as CAR format from stdin, and import to PDS
-**repo root \[did\]**
+**repo head \[did\]**
-> Get the current \'root\' commit for a DID
+> Get the latest commit for a DID
# OPTIONS
diff --git a/extra/adenosine.1.scdoc b/extra/adenosine.1.scdoc
index e6e63ef..aa09334 100644
--- a/extra/adenosine.1.scdoc
+++ b/extra/adenosine.1.scdoc
@@ -107,9 +107,6 @@ body fields. Body fields only used for "post" requests.
*account register --email <email> --password <password> --handle <handle>*
-*account info*
- Fetches account metadata for the current session
-
*account login --password <password> --handle <handle>*
Create a new authenticated session
@@ -124,8 +121,8 @@ body fields. Body fields only used for "post" requests.
*repo import [did]*
Read raw binary repository as CAR format from stdin, and import to PDS
-*repo root [did]*
- Get the current 'root' commit for a DID
+*repo head [did]*
+ Get the latest commit for a DID
# OPTIONS