@@ -47,12 +47,13 @@ type User struct {
4747}
4848
4949type PostRecord struct {
50- Type string `json:"$type"`
51- CreatedAt time.Time `json:"createdAt"`
52- Embed Embed `json:"embed"`
53- Facets []Facet `json:"facets"`
54- Langs []string `json:"langs"`
55- Text string `json:"text"`
50+ Type string `json:"$type"`
51+ CreatedAt time.Time `json:"createdAt"`
52+ Embed Embed `json:"embed"`
53+ Facets []Facet `json:"facets"`
54+ Langs []string `json:"langs"`
55+ Text string `json:"text"`
56+ Reply * ReplySubject `json:"reply,omitempty"`
5657}
5758
5859// Specifically for reposts
@@ -176,16 +177,22 @@ type PostInteractionRecord struct {
176177}
177178
178179type CreatePostRecord struct {
179- Type string `json:"$type"`
180- Text string `json:"text"`
181- CreatedAt time.Time `json:"createdAt"`
180+ Type string `json:"$type"`
181+ Text string `json:"text"`
182+ CreatedAt time.Time `json:"createdAt"`
183+ Reply * ReplySubject `json:"reply,omitempty"`
182184}
183185
184186type Subject struct {
185187 URI string `json:"uri"`
186188 CID string `json:"cid"`
187189}
188190
191+ type ReplySubject struct {
192+ Root Subject `json:"root"`
193+ Parent Subject `json:"parent"`
194+ }
195+
189196type Commit struct {
190197 CID string `json:"cid"`
191198 Rev string `json:"rev"`
@@ -218,6 +225,16 @@ type UserSearchResult struct {
218225 Actors []User `json:"actors"`
219226}
220227
228+ type RecordResponse struct {
229+ URI string `json:"uri"`
230+ CID string `json:"cid"`
231+ Value RecordValue `json:"value"`
232+ }
233+
234+ type RecordValue struct {
235+ Reply * ReplySubject `json:"reply,omitempty"`
236+ }
237+
221238func SendRequest (token * string , method string , url string , body io.Reader ) (* http.Response , error ) {
222239 client := & http.Client {}
223240 req , err := http .NewRequest (method , url , body )
@@ -459,32 +476,34 @@ func GetPost(token string, uri string, depth int, parentHeight int) (error, *Thr
459476
460477// This handles both normal & replys
461478func UpdateStatus (token string , my_did string , status string , in_reply_to * string ) (* ThreadRoot , error ) {
462- url := "https://public. bsky.social/xrpc/com.atproto.repo.createRecord"
479+ url := "https://bsky.social/xrpc/com.atproto.repo.createRecord"
463480
464- reqBody := [] byte {}
481+ var replySubject * ReplySubject
465482 var err error
466483
467- if in_reply_to == nil || * in_reply_to == "" {
468-
469- payload := CreateRecordPayload {
470- Collection : "app.bsky.feed.post" ,
471- Repo : my_did ,
472- Record : CreatePostRecord {
473- Type : "app.bsky.feed.post" ,
474- Text : status ,
475- CreatedAt : time .Now ().UTC (),
476- },
477- }
478-
479- reqBody , err = json .Marshal (payload )
484+ // Replying
485+ if in_reply_to != nil && * in_reply_to != "" {
486+ replySubject , err = GetReplyRefs (token , * in_reply_to )
480487 if err != nil {
481- return nil , errors .New ("failed to marshal payload " )
488+ return nil , errors .New ("failed to fetch reply refs " )
482489 }
490+ }
483491
484- } else {
485- return nil , errors .New ("in_reply_to not implemented" )
492+ payload := CreateRecordPayload {
493+ Collection : "app.bsky.feed.post" ,
494+ Repo : my_did ,
495+ Record : CreatePostRecord {
496+ Type : "app.bsky.feed.post" ,
497+ Text : status ,
498+ CreatedAt : time .Now ().UTC (),
499+ Reply : replySubject ,
500+ },
486501 }
487502
503+ reqBody , err := json .Marshal (payload )
504+ if err != nil {
505+ return nil , errors .New ("failed to marshal payload" )
506+ }
488507 resp , err := SendRequest (& token , http .MethodPost , url , bytes .NewReader (reqBody ))
489508 if err != nil {
490509 return nil , errors .New ("failed to post" )
@@ -505,6 +524,8 @@ func UpdateStatus(token string, my_did string, status string, in_reply_to *strin
505524 return nil , err
506525 }
507526
527+ time .Sleep (100 * time .Millisecond ) // Bluesky doesn't update instantly, so we wait a bit before fetching the post
528+
508529 err , thread := GetPost (token , postData .URI , 0 , 1 )
509530 if err != nil {
510531 return nil , errors .New ("failed to fetch made post" )
@@ -742,3 +763,41 @@ func UserSearch(token string, query string) ([]User, error) {
742763 }
743764 return users .Actors , nil
744765}
766+
767+ // thank you https://docs.bsky.app/blog/create-post#replies
768+ func GetReplyRefs (token string , parentURI string ) (* ReplySubject , error ) {
769+ // Get the parent post
770+ err , parentThread := GetPost (token , parentURI , 0 , 1 )
771+ if err != nil {
772+ return nil , fmt .Errorf ("failed to fetch parent post: %w" , err )
773+ }
774+
775+ // If parent has a reply reference, fetch the root post
776+ var rootURI string
777+ var rootCID string
778+
779+ if parentThread .Thread .Post .Record .Reply != nil {
780+ // Get the root post
781+ rootURI = parentThread .Thread .Post .Record .Reply .Root .URI
782+ err , rootThread := GetPost (token , rootURI , 0 , 1 )
783+ if err != nil {
784+ return nil , fmt .Errorf ("failed to fetch root post: %w" , err )
785+ }
786+ rootCID = rootThread .Thread .Post .CID
787+ } else {
788+ // If parent has no reply reference, it's a top-level post, so it's also the root
789+ rootURI = parentThread .Thread .Post .URI
790+ rootCID = parentThread .Thread .Post .CID
791+ }
792+
793+ return & ReplySubject {
794+ Root : Subject {
795+ URI : rootURI ,
796+ CID : rootCID ,
797+ },
798+ Parent : Subject {
799+ URI : parentThread .Thread .Post .URI ,
800+ CID : parentThread .Thread .Post .CID ,
801+ },
802+ }, nil
803+ }
0 commit comments