spec

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package spec holds every API this CLI knows about.

Contracts ship inside the binary, mirroring the layout of the contracts repository, and are read from there and nowhere else.

There is deliberately no runtime refresh. Letting a local cache change which commands exist would make one released version behave differently on two machines, and "which contract do you have" becomes the first question on every support thread. Contracts travel with the release; a new backend operation arrives with the next one.

Reading OpenAPI still earns its keep without that: the command tree needs no hand-maintained list, and arguments are checked against the contract before a request goes out.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoEmbeddedSpecs = errors.New("embedded contracts are unreadable")

	ErrSpecUnparsable = errors.New("cannot parse contract")
)

Functions

func EmbeddedNames

func EmbeddedNames() ([]string, error)

EmbeddedNames lists the services that ship with a contract.

Types

type Credential

type Credential int

Credential says which of the platform's two user-facing tokens an operation takes.

account token   signed by Keycloak   register, list projects, exchange
access token    signed by IAM        everything inside a project

An access token names a project as well as a person, which is why no request path carries a project id. The contracts still call it a project token, and the product calls it 访问密钥; all three are the same thing.

The exchange itself can only take the account token: it is what mints project tokens, so requiring one would deadlock.

This has nothing to do with the operator console, which this CLI never touches.

const (
	AccessToken Credential = iota

	AccountToken
)

func ReadCredential

func ReadCredential(service string) Credential

ReadCredential is exported because refreshing a contract is a request too, and the account face does not accept a project token.

func (Credential) String

func (c Credential) String() string

type Inputs

type Inputs struct {
	// Path is ordered by the path itself. Reversed, `detach-disk <a> <b>` swaps
	// two UUIDs and the server can only answer 404.
	Path []*openapi3.Parameter

	Query []*openapi3.Parameter

	// Body is the application/json schema, or nil when the operation takes none.
	Body *openapi3.Schema
}

Inputs is what an operation accepts, split the way the contract states it.

This is a fact about the contract, not a decision about any one caller: which parameters live in the path, in what order, and which are query. Both the command tree and the tool surface need exactly this split, and deriving it twice is how two surfaces start disagreeing about one operation.

What each caller does with it differs and stays with the caller. A shell has no way to type an object, so the command tree flattens a body into one flag per field; a tool call is already JSON and hands the schema over as it is.

type Operation

type Operation struct {
	ID      string
	Service string
	Method  string
	Path    string

	Summary     string
	Description string
	Deprecated  bool

	Tags []string

	// Credential decides which token to send. It follows from the service: the
	// account face and the project face are separate services with separate
	// contracts and separate addresses.
	Credential Credential

	// BaseURL is the address its contract declares.
	BaseURL string

	Parameters openapi3.Parameters

	RequestBody *openapi3.RequestBody
	// contains filtered or unexported fields
}

Operation is one API operation as the CLI sees it.

ID is the spec's operationId and the CLI's only anchor: the command tree names commands after it. It is already treated as a stable identifier — both the Go and TypeScript SDKs generate their method names from it — so a command name cannot drift without breaking those too.

func (*Operation) Inputs

func (o *Operation) Inputs() *Inputs

Inputs splits the operation's parameters. Computed once when the contract is read, because every caller wants the same answer and the walk is not free.

func (*Operation) RequiresBody

func (o *Operation) RequiresBody() bool

RequiresBody reports whether the contract insists on one.

type Service

type Service struct {
	Name string

	Version string

	// BaseURL is where this service answers, as its contract declares it.
	//
	// Taken from the contract rather than derived from the service name: the
	// convention <service>.leaflow.cloud holds for every service but one, and
	// the exception answers 404 rather than announcing itself.
	BaseURL string

	Doc *openapi3.T
	// contains filtered or unexported fields
}

func (*Service) Operation

func (s *Service) Operation(id string) (*Operation, bool)

func (*Service) OperationIDs

func (s *Service) OperationIDs() []string

func (*Service) Operations

func (s *Service) Operations() []*Operation

type Set

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

func Load

func Load() (*Set, error)

Load reads every embedded contract.

func (*Set) Names

func (s *Set) Names() []string

func (*Set) Service

func (s *Set) Service(name string) (*Service, bool)

func (*Set) Services

func (s *Set) Services() []*Service

Jump to

Keyboard shortcuts

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