11package linear
22
3- import "time"
3+ import (
4+ "context"
5+ "fmt"
6+ "strings"
7+ "time"
8+
9+ "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
10+ "go.uber.org/zap"
11+ )
412
513type PageInfo struct {
614 EndCursor string `json:"endCursor"`
@@ -93,7 +101,8 @@ type Project struct {
93101type GraphQLError struct {
94102 Error string `json:"error"`
95103 Errors []struct {
96- Message string `json:"message"`
104+ Message string `json:"message"`
105+ Extensions map [string ]interface {} `json:"extensions,omitempty"`
97106 } `json:"errors"`
98107}
99108
@@ -107,6 +116,49 @@ func (e *GraphQLError) Message() string {
107116 return e .Errors [0 ].Message
108117}
109118
119+ // IsRateLimited checks if the error contains Linear's RATELIMITED error code.
120+ func (e * GraphQLError ) IsRateLimited (ctx context.Context ) bool {
121+ // Get logger from context if available, otherwise use a default logger
122+ l := ctxzap .Extract (ctx )
123+
124+ for _ , err := range e .Errors {
125+ // Log the error message and extensions for debugging
126+ l .Info ("checking GraphQL error for rate limiting" ,
127+ zap .String ("message" , err .Message ),
128+ zap .Any ("extensions" , err .Extensions ))
129+
130+ if extensions , ok := err .Extensions ["code" ]; ok {
131+ l .Info ("found 'code' extension" ,
132+ zap .Any ("code_value" , extensions ),
133+ zap .String ("code_type" , fmt .Sprintf ("%T" , extensions )))
134+
135+ if code , ok := extensions .(string ); ok && code == "RATELIMITED" {
136+ l .Info ("rate limited detected via code extension" ,
137+ zap .String ("code" , code ))
138+ return true
139+ } else {
140+ l .Info ("code extension is not 'RATELIMITED'" ,
141+ zap .Any ("got_value" , extensions ),
142+ zap .String ("got_type" , fmt .Sprintf ("%T" , extensions )))
143+ }
144+ } else {
145+ l .Info ("no 'code' extension found" )
146+ }
147+
148+ // Also check the message for backward compatibility
149+ if strings .Contains (strings .ToLower (err .Message ), "ratelimited" ) {
150+ l .Info ("rate limited detected via message" ,
151+ zap .String ("message" , err .Message ))
152+ return true
153+ } else {
154+ l .Info ("message does not contain 'ratelimited'" ,
155+ zap .String ("message" , err .Message ))
156+ }
157+ }
158+ l .Info ("no rate limiting detected in any GraphQL errors" )
159+ return false
160+ }
161+
110162type ViewerPermissions struct {
111163 Guest bool `json:"guest"`
112164 Admin bool `json:"admin"`
0 commit comments