feat(pds-server): app.bsky.actor.profile get/set XRPC endpoints
Read / read-modify-write the authenticated user's profile record
through the standard atproto repo-write path. Auth is checked via
the existing bearer-token helper; the request body's
`display_name` / `description` / `avatar_blob_cid` /
`banner_blob_cid` overlay the existing record (None fields
preserve the old value).
Blob CID ownership: any supplied avatar/banner CID is looked up
in the `blobs` table with `WHERE cid = $1 AND did = $2`,
rejecting with 400 if the blob isn't owned by the authenticated
user. The resolved `mime_type` / `size` is written into the
record so consumers reading `size` for layout decisions get the
real value (previously hardcoded to "image/png" / 0).
Best-effort push to the AppView via `AppViewPushClient::push_profile`
so the `profiles` cache reflects the new avatar / display name
without waiting for the Jetstream replay path.
Wire shape:
GET /xrpc/app.bsky.actor.profile.get
→ { did, handle, profile: { displayName, description, ... } | null }
POST /xrpc/app.bsky.actor.profile.set
body: { displayName, description, avatarBlobCid, bannerBlobCid }
→ same shape as get
Includes `merge_profile_fields` testable helper (4 unit tests
locking the camelCase wire shape and the merge semantics).
The AppView-side indexer arm and the Tauri UI land in the
following two commits.
This commit is contained in:
@@ -38,6 +38,14 @@ impl AppState {
|
||||
"app.bsky.feed.repost".to_string(),
|
||||
Lex::from_json(include_str!("../../../lexicons/app/bsky/feed/repost.json")).unwrap(),
|
||||
);
|
||||
// Profile record — avatar/banner/display name/description.
|
||||
// Validates the createRecord body when the Tauri client calls
|
||||
// its setProfile command. Other fields stay optional so a
|
||||
// brand-new account with an empty profile is legal.
|
||||
lex.lexicons.insert(
|
||||
"app.bsky.actor.profile".to_string(),
|
||||
Lex::from_json(include_str!("../../../lexicons/app/bsky/actor/profile.json")).unwrap(),
|
||||
);
|
||||
let plc_url = cfg.plc_directory_url.clone();
|
||||
// The PDS speaks to the AppView via the cluster-internal URL —
|
||||
// never the public one, because the ingest endpoint is unauth'd
|
||||
|
||||
Reference in New Issue
Block a user