// Package webhook provides functionality for sending and validating webhooks package webhook import ( "errors" "fmt" "net/http" ) // Common webhook error types var ( // ErrInvalidConfig indicates missing or invalid configuration values ErrInvalidConfig = errors.New("invalid webhook configuration") // ErrPayloadMarshall indicates a failure to marshal the webhook payload ErrPayloadMarshall = errors.New("failed to marshal webhook payload") // ErrRequestCreation indicates a failure to create the HTTP request ErrRequestCreation = errors.New("failed to create webhook request") // ErrRequestFailed indicates a permanent failure in the webhook request ErrRequestFailed = errors.New("webhook request failed") // ErrTooManyRequests indicates rate limiting by the webhook endpoint ErrTooManyRequests = errors.New("rate limit exceeded") // ErrMaxRetriesReached indicates all retry attempts have been exhausted ErrMaxRetriesReached = errors.New("maximum retries reached") // ErrInvalidSignature indicates webhook signature validation failed ErrInvalidSignature = errors.New("invalid webhook signature") ) // Error represents a webhook-specific error with detailed context type Error struct { // Op is the operation that failed (e.g., "send", "validate") Op string // Code is the HTTP status code (if applicable) Code int // Err is the underlying error Err error // Details contains additional error context Details string } // Error returns a string representation of the error func (e *Error) Error() string { var msg string if e.Code > 0 { msg = fmt.Sprintf("webhook %s failed with status %d", e.Op, e.Code) } else { msg = fmt.Sprintf("webhook %s failed", e.Op) } if e.Details != "" { msg = fmt.Sprintf("%s: %s", msg, e.Details) } if e.Err != nil { msg = fmt.Sprintf("%s: %v", msg, e.Err) } return msg } // Unwrap returns the underlying error func (e *Error) Unwrap() error { return e.Err } // Is reports whether target matches this error func (e *Error) Is(target error) bool { return errors.Is(e.Err, target) } // NewError creates a new webhook error func NewError(op string, err error, details string) *Error { return &Error{ Op: op, Err: err, Details: details, } } // NewHTTPError creates a new webhook error with HTTP status code func NewHTTPError(op string, code int, err error, details string) *Error { return &Error{ Op: op, Code: code, Err: err, Details: details, } } // IsTemporaryError returns true if the error is temporary and the operation can be retried func IsTemporaryError(err error) bool { var e *Error if errors.As(err, &e) { return e.Code == http.StatusTooManyRequests || (e.Code >= 500 && e.Code <= 599) || e.Is(ErrTooManyRequests) } return false }