@volter/browser-sandboxes
v0.1.313
Published
The hosted backend's control-plane side: a remote runtime client with the in-page runtime's method names, a sandbox manager with Docker and Fly Machines providers, a control plane a page can call, and an MCP server
Readme
@volter/browser-sandboxes
The hosted backend's control-plane side. One sandbox is one host agent from
@volter/browser-host-node; this package creates them, drives them, and
exposes them.
RemoteRuntime(@volter/browser-sandboxes/client.js) is a browser-safe client with the in-page runtime's method names:spawn,start,on,ports,portUrl,request,metrics,openPty,webSocket, and an asynchronousfilessurface including archiveexportandimport. Passingterminaltostartselects the host's PTY allocator behind that same process API; the returned handle streams output and exposesresize,result, andkillwithout a backend-specific launch path.RemoteControlPlaneis the browser-safe lifecycle client: create, inspect, pause, resume, snapshot, restore, fork, and destroy, plus aRemoteRuntimethrough the plane's token-hiding agent proxy.SandboxManagercreates sandboxes through a provider with four calls,start,pause,resume,stop, returns a remote runtime per sandbox, reaps idle ones from the agent's own activity report, forks workspaces, snapshots and restores the portable workspace boundary, and passes templates, volumes, and limits through. Snapshot metadata explicitly says that process state is excluded.DockerProviderruns the agent image as a local container.FlyProviderdrives the Fly Machines API, the Fly twin offline or Fly itself, reaching machines through flyctl's WireGuard proxy.serveControlPlaneis an HTTP server a page can call that proxies each sandbox's agent with the token held server-side.serveMcpspeaks the Model Context Protocol over stdio with tools for sandboxes, commands, files, ports, and guest requests.moveWorkspace,mirrorWorkspace, andreturnWorkspace(@volter/browser-sandboxes/transfer.js, browser-safe) move a workspace into a sandbox without its dependency trees, name the install command its lockfile implies, keep the two copies the same while the work runs there, and bring the sandbox's work back without the sandbox's tree.
import { DockerProvider, SandboxManager } from "@volter/browser-sandboxes";
const manager = new SandboxManager({ provider: new DockerProvider({ image: "substrate-node-host:local" }) });
const sandbox = await manager.create();
const result = await sandbox.runtime.spawn("echo $((21 * 2))", { cwd: "/workspace" });
await sandbox.kill();Run the hosted tier yourself
Everything needed is in this repository under the MIT license.
- Build the guest image, which carries the kernel and
@volter/browser-host-node:node examples/node-host/build-image.mjs(add--platform linux/amd64for x86 hosts such as Fly Machines). - On a machine with Docker, start a control plane with
browser-substrate-control-plane; it creates one container per sandbox from that image and proxies each sandbox's agent under/v1/sandboxes/<id>/agent/with the token held server-side. Point a page or the MCP server (browser-substrate-mcp) at it. - On Fly Machines, push the image to your app's registry and set
SUBSTRATE_PROVIDER=fly,FLY_APP,FLY_IMAGE,FLY_REGION, andFLY_API_TOKEN; the provider reaches machines through flyctl's WireGuard proxy using your existing login. A stopped machine restarts from a clean rootfs, so create sandboxes with avolumewhen the workspace must survive pause and resume.
The hybrid page
examples/node-host/hybrid is the reference consumer: one page that runs a
project in the tab, decides placement, and moves the workspace to a sandbox
and back through the transfer helper. npm run dev:hybrid:control-plane
starts a self-hosted plane on port 4291 and npm run dev:hybrid serves the
page on 4292; HYBRID_PORT and CONTROL_PLANE_PORT give a second copy its
own ports. CONTROL_PLANE_URL points the page's proxy at a remote plane
instead, with CONTROL_PLANE_IP pinning its address while a name propagates.
Against a managed plane the page's dev server stands in for the adopter's
server: it registers an account, or uses SUBSTRATE_ACCOUNT_KEY, passes
SUBSTRATE_REGISTRATION_CODE when the plane requires one, and mints a
session per visitor; the tab never holds a key. verify:node-host:transfer
with TRANSFER_PROJECT naming a project with a lockfile and installed
dependencies measures the move, the far-side install, the mirror, and the
return.
The wire
The agent speaks substrate-agent/1 and the control plane
substrate-control-plane/1. Each describes itself at its unversioned root
with its protocol, version, base path, route catalogue, and capabilities,
serves every route under /v1, carries x-substrate-protocol on every
response, and answers 426 to a client stating another version.
RemoteRuntime negotiates GET / before it trusts the wire and refuses a
server speaking another protocol or version with the reason. The agent's
/v1 stays visible through the control plane's prefix, so one client class
drives a bare agent and a proxied one alike. runHostedContract walks the
catalogue against any live server; a managed service that passes it speaks
the same API as this self-hosted tier.
