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 ¶
var ( ErrNoEmbeddedSpecs = errors.New("embedded contracts are unreadable") ErrSpecUnparsable = errors.New("cannot parse contract") )
Functions ¶
func EmbeddedNames ¶
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 ¶
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 ¶
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
}