Files
Andrey NeringandGitHub a14feb3ef1 feat: launch hyper beta (#2768)
No need to set `HYPERCRUSH=1` anymore.
2026-04-30 21:53:01 +00:00

84 lines
2.0 KiB
Go

// Package hyper provides a fantasy.Provider that proxies requests to Hyper.
package hyper
import (
"cmp"
"context"
_ "embed"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os"
"sync"
"time"
"charm.land/catwalk/pkg/catwalk"
)
//go:generate wget -O provider.json https://hyper.charm.land/v1/provider
//go:embed provider.json
var embedded []byte
// Embedded returns the embedded Hyper provider.
var Embedded = sync.OnceValue(func() catwalk.Provider {
var provider catwalk.Provider
if err := json.Unmarshal(embedded, &provider); err != nil {
slog.Error("Could not use embedded provider data", "err", err)
}
if e := os.Getenv("HYPER_URL"); e != "" {
provider.APIEndpoint = e + "/api/v1/fantasy"
}
return provider
})
const (
// Name is the default name of this meta provider.
Name = "hyper"
// DisplayName is the display name of Hyper.
DisplayName = "Charm Hyper"
// defaultBaseURL is the default proxy URL.
defaultBaseURL = "https://hyper.charm.land"
)
// BaseURL returns the base URL, which is either $HYPER_URL or the default.
var BaseURL = sync.OnceValue(func() string {
return cmp.Or(os.Getenv("HYPER_URL"), defaultBaseURL)
})
// FetchCredits calls the Hyper /v1/credits endpoint and returns the remaining
// credits count.
func FetchCredits(ctx context.Context, apiKey string) (int, error) {
req, err := http.NewRequestWithContext(
ctx,
http.MethodGet,
BaseURL()+"/v1/credits",
nil,
)
if err != nil {
return 0, fmt.Errorf("could not create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return 0, fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close() //nolint:errcheck
if resp.StatusCode != http.StatusOK {
return 0, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
var result struct {
Balance int `json:"balance"`
}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return 0, fmt.Errorf("failed to decode response: %w", err)
}
return result.Balance, nil
}