@@ -252,7 +252,8 @@ func (c *Client) DeletePost(ctx context.Context, postID string) error {
252252}
253253
254254// IterPosts returns a channel that yields posts with automatic pagination.
255- // Close the returned context cancel function when done to stop iteration.
255+ // Cancel the context to stop iteration early. Rate limit errors are handled
256+ // automatically — the iterator waits and retries instead of propagating them.
256257func (c * Client ) IterPosts (ctx context.Context , opts * IterPostsOptions ) <- chan IterResult [Post ] {
257258 ch := make (chan IterResult [Post ])
258259 go func () {
@@ -276,6 +277,14 @@ func (c *Client) IterPosts(ctx context.Context, opts *IterPostsOptions) <-chan I
276277 for {
277278 result , err := c .GetPosts (ctx , & getOpts )
278279 if err != nil {
280+ if delay := rateLimitDelay (err ); delay > 0 {
281+ select {
282+ case <- time .After (delay ):
283+ continue
284+ case <- ctx .Done ():
285+ return
286+ }
287+ }
279288 select {
280289 case ch <- IterResult [Post ]{Err : err }:
281290 case <- ctx .Done ():
@@ -354,7 +363,9 @@ func (c *Client) GetAllComments(ctx context.Context, postID string) ([]Comment,
354363 return all , nil
355364}
356365
357- // IterComments returns a channel that yields comments with automatic pagination.
366+ // IterComments returns a channel that yields comments with automatic
367+ // pagination. Cancel the context to stop iteration early. Rate limit errors
368+ // are handled automatically.
358369func (c * Client ) IterComments (ctx context.Context , postID string , maxResults int ) <- chan IterResult [Comment ] {
359370 ch := make (chan IterResult [Comment ])
360371 go func () {
@@ -363,6 +374,15 @@ func (c *Client) IterComments(ctx context.Context, postID string, maxResults int
363374 for page := 1 ; ; page ++ {
364375 result , err := c .GetComments (ctx , postID , page )
365376 if err != nil {
377+ if delay := rateLimitDelay (err ); delay > 0 {
378+ select {
379+ case <- time .After (delay ):
380+ page -- // retry same page
381+ continue
382+ case <- ctx .Done ():
383+ return
384+ }
385+ }
366386 select {
367387 case ch <- IterResult [Comment ]{Err : err }:
368388 case <- ctx .Done ():
@@ -388,51 +408,65 @@ func (c *Client) IterComments(ctx context.Context, postID string, maxResults int
388408 return ch
389409}
390410
411+ // rateLimitDelay returns the wait duration if err is a RateLimitError, or 0.
412+ func rateLimitDelay (err error ) time.Duration {
413+ if rle , ok := err .(* RateLimitError ); ok {
414+ if rle .RetryAfter > 0 {
415+ return time .Duration (rle .RetryAfter ) * time .Second
416+ }
417+ return 2 * time .Second // default wait
418+ }
419+ return 0
420+ }
421+
391422// --- Voting ---
392423
393- // VotePost upvotes (+1) or downvotes (-1) a post.
394- func (c * Client ) VotePost (ctx context.Context , postID string , value int ) (map [string ]any , error ) {
424+ // VotePost upvotes (+1) or downvotes (-1) a post. Pass 1 for upvote, -1 for
425+ // downvote. Passing 0 defaults to upvote.
426+ func (c * Client ) VotePost (ctx context.Context , postID string , value int ) (* VoteResponse , error ) {
395427 if value == 0 {
396428 value = 1
397429 }
398- var resp map [ string ] any
430+ var resp VoteResponse
399431 if err := c .do (ctx , http .MethodPost , "/posts/" + postID + "/vote" , map [string ]any {"value" : value }, & resp ); err != nil {
400432 return nil , err
401433 }
402- return resp , nil
434+ return & resp , nil
403435}
404436
405- // VoteComment upvotes (+1) or downvotes (-1) a comment.
406- func (c * Client ) VoteComment (ctx context.Context , commentID string , value int ) (map [string ]any , error ) {
437+ // VoteComment upvotes (+1) or downvotes (-1) a comment. Pass 1 for upvote,
438+ // -1 for downvote. Passing 0 defaults to upvote.
439+ func (c * Client ) VoteComment (ctx context.Context , commentID string , value int ) (* VoteResponse , error ) {
407440 if value == 0 {
408441 value = 1
409442 }
410- var resp map [ string ] any
443+ var resp VoteResponse
411444 if err := c .do (ctx , http .MethodPost , "/comments/" + commentID + "/vote" , map [string ]any {"value" : value }, & resp ); err != nil {
412445 return nil , err
413446 }
414- return resp , nil
447+ return & resp , nil
415448}
416449
417450// --- Reactions ---
418451
419- // ReactPost toggles an emoji reaction on a post.
420- // Emoji should be a key like "fire", "heart", "rocket", etc .
421- func (c * Client ) ReactPost (ctx context.Context , postID , emoji string ) (map [ string ] any , error ) {
422- var resp map [ string ] any
452+ // ReactPost toggles an emoji reaction on a post. Use the Emoji* constants
453+ // (e.g. [EmojiFire], [EmojiHeart]) or pass a raw key string .
454+ func (c * Client ) ReactPost (ctx context.Context , postID , emoji string ) (* ReactionResponse , error ) {
455+ var resp ReactionResponse
423456 if err := c .do (ctx , http .MethodPost , "/posts/" + postID + "/react" , map [string ]any {"emoji" : emoji }, & resp ); err != nil {
424457 return nil , err
425458 }
426- return resp , nil
459+ return & resp , nil
427460}
428461
429- // ReactComment toggles an emoji reaction on a comment.
430- func (c * Client ) ReactComment (ctx context.Context , commentID , emoji string ) (map [string ]any , error ) {
431- var resp map [string ]any
462+ // ReactComment toggles an emoji reaction on a comment. Use the Emoji*
463+ // constants or pass a raw key string.
464+ func (c * Client ) ReactComment (ctx context.Context , commentID , emoji string ) (* ReactionResponse , error ) {
465+ var resp ReactionResponse
432466 if err := c .do (ctx , http .MethodPost , "/comments/" + commentID + "/react" , map [string ]any {"emoji" : emoji }, & resp ); err != nil {
433467 return nil , err
434468 }
435- return resp , nil
469+ return & resp , nil
436470}
437471
438472// --- Polls ---
@@ -446,13 +480,13 @@ func (c *Client) GetPoll(ctx context.Context, postID string) (*PollResults, erro
446480 return & resp , nil
447481}
448482
449- // VotePoll casts a vote on a poll.
450- func (c * Client ) VotePoll (ctx context.Context , postID string , optionIDs []string ) (map [ string ] any , error ) {
451- var resp map [ string ] any
483+ // VotePoll casts a vote on a poll. Pass one or more option IDs.
484+ func (c * Client ) VotePoll (ctx context.Context , postID string , optionIDs []string ) (* PollVoteResponse , error ) {
485+ var resp PollVoteResponse
452486 if err := c .do (ctx , http .MethodPost , "/posts/" + postID + "/poll/vote" , map [string ]any {"option_ids" : optionIDs }, & resp ); err != nil {
453487 return nil , err
454488 }
455- return resp , nil
489+ return & resp , nil
456490}
457491
458492// --- Messaging ---
@@ -658,13 +692,13 @@ func (c *Client) MarkNotificationRead(ctx context.Context, notificationID string
658692
659693// --- Colonies ---
660694
661- // GetColonies lists all colonies.
662- func (c * Client ) GetColonies (ctx context.Context , limit int ) ([]Colony , error ) {
695+ // GetColonies lists all colonies (sub-communities) .
696+ func (c * Client ) GetColonies (ctx context.Context , limit int ) ([]SubColony , error ) {
663697 if limit <= 0 {
664698 limit = 50
665699 }
666700 q := url.Values {"limit" : {strconv .Itoa (limit )}}
667- var resp []Colony
701+ var resp []SubColony
668702 if err := c .do (ctx , http .MethodGet , "/colonies?" + q .Encode (), nil , & resp ); err != nil {
669703 return nil , err
670704 }
0 commit comments