platform

package
v6.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package platform builds the generated API client with what every request needs: authentication, a User-Agent, request logging, and retries that are safe to make.

Index

Constants

View Source
const PageSize int32 = 100

PageSize is the most items a paged endpoint returns at once.

Variables

View Source
var (
	// RetryUnit is the base of every wait between attempts: the backoff after a transport
	// failure, and a 429 without a reset header. Tests shorten it.
	RetryUnit = time.Second
	// MaxRateLimitWait bounds the total time spent waiting out 429s for one request.
	MaxRateLimitWait = 2 * time.Minute
)
View Source
var DefaultBucket = Bucket{Burst: 100, RefillTokens: 25, RefillInterval: 15 * time.Second}
View Source
var ErrNoAccessToken = errors.New("no API access token")

ErrNoAccessToken is reported with the setup help, before any request is made.

View Source
var Verbose bool
View Source
var Version = "dev"

Version is set at build time for releases, with -ldflags -X, which only works on a variable initialised to a constant. Read it through CurrentVersion.

Functions

func AllPages

func AllPages[T any](fetch func(page, size int32) (*http.Response, error)) ([]T, error)

AllPages follows nextPage until the last page: a listing cut at the first response would silently leave the rest out.

func AllPagesRaw

func AllPagesRaw(fetch func(page, size int32) (*http.Response, error)) ([]json.RawMessage, error)

AllPagesRaw is AllPages keeping each item as the platform sent it, for commands that print the items themselves with -t json or --jq.

func Check

func Check(resp *http.Response, body []byte) error

Check turns any non-2xx response into an APIError.

func CurrentVersion

func CurrentVersion() string

CurrentVersion is the release version, or for a binary built with `go install`, the module version its build info carries.

func Decode

func Decode(resp *http.Response, err error, target any) (*http.Response, error)

Decode reads a response into target.

func Failed

func Failed(err error, format string, args ...any) error

Failed reports a failed request as the TypeScript CLI did: the message, the request error, and the platform's problem body pretty-printed, which is what names the violated constraint.

func IsStatus

func IsStatus(err error, status int) bool

func MissingTokenHelp

func MissingTokenHelp() string

func Read

func Read(resp *http.Response, err error) ([]byte, *http.Response, error)

Read takes a generated client call's result and returns the body, failing on any status outside 2xx.

func ReadDocument

func ReadDocument(resp *http.Response, err error) (*output.Document, *http.Response, error)

ReadDocument reads a response as an order-preserving document.

func SetLimiter

func SetLimiter(l *RateLimiter)

SetLimiter replaces the shared limiter. Tests use it so that a suite's requests are not paced to the platform's allowance.

func WithTimeout

func WithTimeout(ctx context.Context, d time.Duration) context.Context

WithTimeout gives the requests made with ctx a longer deadline than the default 30 seconds, as artifact downloads need.

Types

type APIError

type APIError struct {
	Method, URL string
	Status      int
	Body        []byte
}

APIError carries the status and the problem body of a failed request.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) ProblemType

func (e *APIError) ProblemType() string

ProblemType is the `type` of an RFC 7807 problem body, if there is one.

type Bucket

type Bucket struct {
	Burst          int
	RefillTokens   int
	RefillInterval time.Duration
}

The platform limits requests with a token bucket: a burst of 100, refilled by 25 every 15 seconds. A fan-out like `experiment dump` issues far more than that, and every rejected request would retry into the window it just exhausted, so requests are paced to the documented allowance from the first one. The ratelimit-* headers cannot be used instead: they appear only on the 429 itself, and report the burst but not the refill.

func BucketFromEnvironment

func BucketFromEnvironment() Bucket

BucketFromEnvironment reads the STEADYBIT_RATE_LIMIT_* overrides. An invalid value is warned about rather than ignored quietly, since it would change how hard the CLI hits the platform.

type Client

type Client struct {
	*api.ClientWithResponses
	BaseURL string
	// contains filtered or unexported fields
}

func New

func New() (*Client, error)

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string) (*http.Response, error)

Get fetches a path the spec has no operation for, such as the Location of a run.

func (*Client) GetAnonymously added in v6.1.0

func (c *Client) GetAnonymously(ctx context.Context, path string) (*http.Response, error)

GetAnonymously fetches a path without the access token, as a README showing a badge does: with the token, the platform takes the tenant from it and ignores a wrong one in the URL.

type Clock

type Clock interface {
	Now() time.Time
	// Sleep waits for d, or until ctx ends, and then returns ctx's error.
	Sleep(ctx context.Context, d time.Duration) error
}

Clock is injected so tests can drive the bucket deterministically.

type RateLimiter

type RateLimiter struct {
	// contains filtered or unexported fields
}

func Limiter

func Limiter() *RateLimiter

Limiter is built on first use, so that a command that sends nothing never reads, or complains about, the environment.

func NewRateLimiter

func NewRateLimiter(bucket Bucket, clock Clock) *RateLimiter

func (*RateLimiter) DurationFor

func (r *RateLimiter) DurationFor(count int) time.Duration

DurationFor is how long `count` requests take once the burst is spent, which makes the scale of a large dump visible before it starts rather than an hour into it.

func (*RateLimiter) Wait

func (r *RateLimiter) Wait(ctx context.Context) error

Wait blocks until a request may be sent, or until ctx ends. Each caller takes the next token under the lock, even one not refilled yet, and then sleeps until it is due, so concurrent callers cannot spend the same token and one that gives up hands it back.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL