errors.go

 1package fantasy
 2
 3import (
 4	"fmt"
 5	"net/http"
 6
 7	"github.com/charmbracelet/x/exp/slice"
 8)
 9
10// Error is a custom error type for the fantasy package.
11type Error struct {
12	Message string
13	Title   string
14	Cause   error
15}
16
17func (err *Error) Error() string {
18	if err.Title == "" {
19		return err.Message
20	}
21	return fmt.Sprintf("%s: %s", err.Title, err.Message)
22}
23
24func (err Error) Unwrap() error {
25	return err.Cause
26}
27
28// ProviderError represents an error returned by an external provider.
29type ProviderError struct {
30	Message string
31	Title   string
32	Cause   error
33
34	URL             string
35	StatusCode      int
36	RequestBody     []byte
37	ResponseHeaders map[string]string
38	ResponseBody    []byte
39}
40
41func (m *ProviderError) Error() string {
42	if m.Title == "" {
43		return m.Message
44	}
45	return fmt.Sprintf("%s: %s", m.Title, m.Message)
46}
47
48// IsRetryable checks if the error is retryable based on the status code.
49func (m *ProviderError) IsRetryable() bool {
50	return m.StatusCode == http.StatusRequestTimeout || m.StatusCode == http.StatusConflict || m.StatusCode == http.StatusTooManyRequests
51}
52
53// RetryError represents an error that occurred during retry operations.
54type RetryError struct {
55	Errors []error
56}
57
58func (e *RetryError) Error() string {
59	if err, ok := slice.Last(e.Errors); ok {
60		return fmt.Sprintf("retry error: %v", err)
61	}
62	return "retry error: no underlying errors"
63}
64
65func (e RetryError) Unwrap() error {
66	if err, ok := slice.Last(e.Errors); ok {
67		return err
68	}
69	return nil
70}