Add a simple profile edit page #115
Labels
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente#115
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A simple profile page, where things like display name and avatar can be changed. Should hook into the standard way of doing this on ATProto, so something like an existing lexicon, instead of inventing our own. We probably need to request new permissions for this, but keep the requested ones as minimal as possible and if possible, explain why it's needed.
🤖 On it — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
granularonce a PDS accepts the narrow scopes #129Pushed
claude/issue-115.What I built
/profile— reached by tapping your own face at the top of the account menu (the identity block is now the door; no fifth menu row saying the same thing). It shows your account and, where the deployment allows it, edits your display name and avatar.It hooks into the standard lexicon, not an invented one: the
app.bsky.actor.profilerecord at rkeyself, read withcom.atproto.repo.getRecord, written withputRecord, avatar uploaded withuploadBlob. So a name set here is the name the Bluesky app shows tomorrow.The permission — and why the default is still "none"
The narrowest scope the OAuth spec can express for this is
repo:app.bsky.actor.profile+blob:image/*: one collection, one media type, no posts, follows, likes or preferences. No account server accepts it yet. Measured today:Same answer from
pds.ponente.appandpds.grandiras.net(both the officialghcr.io/bluesky-social/pdsimage). An unknown scope is rejected, not narrowed — asking for the granular pair today breaks sign-in for every member at once. The only scope that works istransition:generic, whose consent screen covers the whole account, to write one record.Handing over everyone's account so they can change a name on a card is your call, not this branch's, so it's configuration:
AtProto:ProfileScope=none(default) |granular(spec-correct, ready for the day a server takes it) |generic(works now). An unrecognised value reads asnone. The app logs which of the three at every start, and the page itself explains to the member which permission was asked and why. Withnonethe page still works — it shows your account and re-fetches Ponente's cached copy of your name and picture (useful on its own: that's the fix for an avatar here that's still the one you replaced elsewhere last year). One caveat when you do turn it on: everyone already signed in holds anatproto-only token, so the page shows them a "sign in again" link rather than a 403 mid-save.Set it with
ATPROTO_PROFILE_SCOPE=genericindeploy/.env. Reasoning and the dated measurement are indocs/auth.md.Details worth knowing
ProfileRecorddrops every field it has no property for — including the self-labels behind "no logged-out visibility". Renaming yourself is not a reason to un-hide your account from the logged-out web. Pinned byProfileRecordTests.swapRecordcarries the CID just read, so a change made in another app meanwhile is a translated sentence and a re-read, not a silent overwrite.MemberService.UpdateProfileAsync→RefreshProfileAsync(a lookup elsewhere; blank name means "not found"), plus a newSetProfileAsync(the member speaking; blank means blank). NewBoardNotifier.ProfileChanged, so the nav header swaps the face in the corner without a reload.Changelog.Unreleasedbullet, anddocs/auth.md/ui.md/orientation.md/README/.env.exampleupdated.What I verified
dotnet buildanddotnet testgreen — 373 passing, including 22 new (ProfileScopeTests,ProfileRecordTests) andDocumentationTests./tmp, not committed) with a seeded OAuth token, and did the save from a real browser.uploadBlobgot the 1524-byte PNG;putRecordcarriedswapRecord, the newdisplayName, the new avatar blob — and the untoucheddescription,createdAtand!no-unauthenticatedself-label. The screenshots above are that run. The nav header avatar updated live.tests/e2e/profile.spec.js(three tests, written following the existing specs). The e2e suite needs the compose stack and this runner has no container engine, so it is unverified — worth a localnpx playwright test profilebefore merging. Note it can only ever cover the read-only half:/dev/login/{did}stores no OAuth token by design, so the editable half is a manual check withATPROTO_PROFILE_SCOPEset.⏱ 110m 28s · 180 turns · tokens: 546.7k in / 110.9k out (+34161.1k cache-read)
📜 Full session transcript
→ Opened PR: #128
→ Filed follow-up issue #129: Switch AtProto:ProfileScope to
granularonce a PDS accepts the narrow scopes→ Filed follow-up issue #130: MemberService.UpdateDisplayNameAsync and UpdateAvatarAsync have no callers