Solari

VMs

github.com/solari-sdk/solari-sandbox-go, package solari. A VM is a session created with Create() and Kind: KindDesktop. It returns the same Sandbox handle a sandbox uses, plus StreamURL for the live view. Driving the GUI is not part of this surface. See the Go SDK hub for install and configuration.

go get github.com/solari-sdk/solari-sandbox-go
Lifecycle and compute, not GUI control
You can create a VM, reach its stream URL, and use Commands, Files, Code, and Git on it. Mouse, keyboard, screenshot, display, and clipboard have no Go binding. See What you cannot do.

Contents

Client

The same Client that creates sandboxes. There is no separate CreateDesktop(): the flavour is a field on CreateOptions.

Methods

Create()

func (c *Client) Create(ctx context.Context, opts CreateOptions) (*Sandbox, error)

With Kind: KindDesktop, provisions a GUI VM (POST /sandboxes) and returns a handle. Retry-safe, since it sends an idempotency key. The control channel is not opened yet.

Parameters:

  • ctx context.Context.
  • opts CreateOptions: set Kind: solari.KindDesktop. An empty Kind defaults to KindSandbox. Template, CPU, MemMb, Envs, Metadata, and Lifecycle all apply, plus the desktop-only Resolution (e.g. "1280x720") and Record. See CreateOptions.

Returns: (*Sandbox, error), with Kind of KindDesktop and StreamURL set.

Errors: *PlanError (402 FeatureRequiresPlan) when the org lacks the desktop entitlement; also *AuthError, *ConcurrencyLimitError, *NoCapacityError, or *GatewayError.

Example:

import solari "github.com/solari-sdk/solari-sandbox-go"

client, _ := solari.NewClient(solari.ClientOptions{
    APIKey:  os.Getenv("SOLARI_API_KEY"),
    BaseURL: "https://api.getsolari.com",
})

vm, err := client.Create(ctx, solari.CreateOptions{
    Template: "office",
    Kind:     solari.KindDesktop,
    CPU:      2,
    MemMb:    4096,
})
if err != nil {
    log.Fatal(err)
}
defer vm.Kill(ctx)

fmt.Println(vm.Kind)       // "desktop"
fmt.Println(vm.StreamURL)  // wss://.../stream/<id>

// Core namespaces work on a VM exactly as on a sandbox.
r, _ := vm.Commands.Run(ctx, "xdotool", solari.CommandOptions{
    Args: []string{"getactivewindow"},
})
fmt.Println(r.Stdout)
Detecting the entitlement error
errors.As unwraps to the typed error, so a 402 is distinguishable from a capacity or auth failure:
var pe *solari.PlanError; if errors.As(err, &pe) { /* needs the desktop plan */ }

Connect()

func (c *Client) Connect(ctx context.Context, sandboxID string) (*Sandbox, error)

Re-attaches to a running VM by id. Reads its view, then derives both the control URL and the stream URL from the gateway origin.

Parameters:

  • ctx context.Context.
  • sandboxID string: the session id.

Returns: (*Sandbox, error). StreamURL is set when the session is a desktop, and empty otherwise.

Errors: *GatewayError if the id is unknown.

Example:

vm, err := client.Connect(ctx, "vm_abc123")
if err != nil {
    log.Fatal(err)
}
if vm.StreamURL != "" {
    fmt.Println("live view:", vm.StreamURL)
}
The stream URL is derived by design
SandboxView has no StreamURL field because the gateway’s toSandboxView never emits one. So Connect builds it as wsOrigin() + "/stream/" + id, the same way ControlURL has always been derived, and the result is identical to what Create decodes off the wire. This is intentional: adding a field the wire never populates would always unmarshal to the zero value. Do not "fix" it.

Sandbox

A live session, GUI or headless. Construct via Create() or Connect().

Fields

Kind

Kind SandboxKind

The session flavour: KindDesktop ("desktop") or KindSandbox ("sandbox").

Example:

if vm.Kind == solari.KindDesktop { /* has a display */ }

StreamURL

StreamURL string

The wss:// RFB URL of the live view, carried from CreateSandboxResponse onto the handle. Hand it to a noVNC client to render or embed the screen.

Value: set for KindDesktop, empty for KindSandbox. A headless sandbox has no display, so an empty string is the correct answer, not a gap.

Example:

if vm.StreamURL == "" {
    log.Fatal("not a desktop")
}

Inherited members

Everything on the Sandbox page works unchanged on a VM: Connect(), Reconnect(), Connected(), Close(), Pause(), Resume(), Kill(), ID, ControlURL, ExpiresAt, and the Commands, Files, Code, and Git namespaces.

What you cannot do

There is no Go GUI surface and no Desktop type. These have no binding:

  • mouse.*, keyboard.*: pointer and key input.
  • screenshot(): capture the screen as bytes.
  • display.*, clipboard.*, open(): resolution, cursor, guest clipboard, launching apps.
  • record.*: in-guest video capture.

Session-level Pause()/Resume() (snapshot the whole VM and bring it back) are ported — see Sandbox.Pause in inherited members above. Only in-guest screen recording has no Go binding.

To drive the GUI, use the TypeScript SDK (the complete reference surface) or the VM HTTP API. Mixing is supported: create and drive from TypeScript, then Connect() a Go handle to the same id for the compute work. One API key, one session, two clients.