Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
1package atproto
2
3import (
4 "encoding/json"
5 "fmt"
6 "net/http"
7)
8
9// Profile holds resolved ATProto profile information fetched at runtime
10type Profile struct {
11 DID string `json:"did"`
12 Handle string `json:"handle"`
13 DisplayName string `json:"displayName"`
14 Avatar string `json:"avatar"`
15 PDSURL string `json:"pdsUrl"`
16}
17
18const bskyAppViewURL = "https://public.api.bsky.app"
19
20// ResolveProfile fetches a user's profile from the Bluesky public AppView.
21func ResolveProfile(did string) (*Profile, error) {
22 url := fmt.Sprintf("%s/xrpc/app.bsky.actor.getProfile?actor=%s", bskyAppViewURL, did)
23
24 resp, err := httpClient.Get(url)
25 if err != nil {
26 return nil, err
27 }
28 defer resp.Body.Close()
29
30 if resp.StatusCode != http.StatusOK {
31 return nil, fmt.Errorf("profile fetch failed: %d", resp.StatusCode)
32 }
33
34 var result struct {
35 DID string `json:"did"`
36 Handle string `json:"handle"`
37 DisplayName string `json:"displayName"`
38 Avatar string `json:"avatar"`
39 }
40
41 if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
42 return nil, err
43 }
44
45 return &Profile{
46 DID: result.DID,
47 Handle: result.Handle,
48 DisplayName: result.DisplayName,
49 Avatar: result.Avatar,
50 }, nil
51}
52
53// GetDisplayName returns the best available name for a user
54func (p *Profile) GetDisplayName() string {
55 if p.DisplayName != "" {
56 return p.DisplayName
57 }
58 if p.Handle != "" && p.Handle != p.DID {
59 return p.Handle
60 }
61 return p.DID
62}