VMs
solari creates GUI VMs with Client::createDesktop() and hands back the same Sandbox handle a sandbox uses, plus streamUrl() for the live view. Driving the GUI is not part of this surface. See the C++ SDK hub for install and configuration.
#include <solari/solari.hpp> // umbrella headercommands, files, code, and git on it. Mouse, keyboard, screenshot, display, and clipboard have no C++ binding. See What you cannot do.Contents
Client
The same Client that creates sandboxes. Only the VM-specific calls are documented here.
Methods
createDesktop()
std::shared_ptr<Sandbox> createDesktop(const CreateSandboxOptions& opts = {})POST /sandboxes with kind: "desktop": creates a GUI VM and returns a handle. Retry-safe: it sends a fresh idempotency key. Routes through the pre-existing SandboxKind::Desktop via a private createWithKind.
Parameters:
optsCreateSandboxOptions: the same struct create() takes. See CreateSandboxOptions.
Returns: std::shared_ptr<Sandbox>, not connected; call connect() before any RPC. kind() is "desktop" and streamUrl() is set.
Throws: PlanError (402 FeatureRequiresPlan) when the org lacks the desktop entitlement; also AuthError, ConcurrencyLimitError, NoCapacityError, or GatewayError.
Example:
solari::ClientOptions co;
co.apiKey = "slr_live_...";
co.baseUrl = "https://api.getsolari.com";
solari::Client client(co);
solari::CreateSandboxOptions o;
o.template_ = "office"; // trailing underscore: "template" is a C++ keyword
o.cpu = 2;
o.memMb = 4096;
auto vm = client.createDesktop(o);
vm->connect();
std::cout << vm->kind() << "\n"; // "desktop"
std::cout << *vm->streamUrl() << "\n"; // wss://.../stream/<id>
// Core namespaces work on a VM exactly as on a sandbox.
solari::CommandOptions ro;
ro.args = {"getactivewindow"};
auto r = vm->commands.run("xdotool", ro);
std::cout << r.stdout_ << "\n";
vm->kill();SandboxKind::Sandbox. Existing code keeps its behaviour.connect()
std::shared_ptr<Sandbox> connect(const std::string& sandboxId)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:
sandboxIdconst std::string&: the session id.
Returns: std::shared_ptr<Sandbox>. streamUrl() holds a value when the session is a desktop, and is std::nullopt otherwise.
Throws: GatewayError if the id is unknown.
Example:
auto vm = client.connect("vm_abc123");
if (auto url = vm->streamUrl()) {
std::cout << "live view: " << *url << "\n";
}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 createDesktop() parses off the wire. This is intentional: adding a field the wire never populates would always be empty. Do not "fix" it.Sandbox
A live session, GUI or headless. Construct via createDesktop() or connect(); never directly.
Properties
kind()
const std::string& kind() constThe session flavour: "desktop" or "sandbox".
Returns: const std::string&
Example:
if (vm->kind() == "desktop") { /* has a display */ }streamUrl()
const std::optional<std::string>& streamUrl() constThe wss:// RFB URL of the live view. Hand it to a noVNC client to render or embed the screen.
Returns: const std::optional<std::string>&: engaged for a desktop, std::nullopt for a sandbox. A headless sandbox has no display, so nullopt is the correct answer, not a gap.
Example:
const auto& url = vm->streamUrl();
if (!url) throw std::runtime_error("not a desktop");Inherited members
Everything on the Sandbox page works unchanged on a VM: connect(), close(), kill(), pause(), resume(), id(), controlUrl(), expiresAt(), connected(), and the commands, files, code, and git members.
What you cannot do
There is no C++ GUI surface. These have no binding and no planned one on this page:
mouse.*,keyboard.*: pointer and key input.screenshot(): capture the screen as bytes.display.*,clipboard.*,open(): resolution, cursor, guest clipboard, launching apps.record.*: in-guest capture (server-side recording viaCreateSandboxOptions::recordis separate and does work — see CreateSandboxOptions).
pause() snapshots RAM+disk and frees the host slot; resume() brings it back on a fresh slot and reopens the control channel. They are GUI-agnostic lifecycle calls, not GUI control, which is why they are documented on the Sandbox page rather than here.To drive the GUI, use the TypeScript SDK (the complete reference surface) or the VM HTTP API. A split-process design works well: drive the VM from a language that has the binding, and keep C++ for the compute-heavy side against the same session id.
