Complete API reference for the BoxLite Node.js/TypeScript SDK.
Node.js: 18+ Platforms: macOS (Apple Silicon), Linux (x86_64, ARM64)
- Runtime Management
- Box Handle
- Network Tunnels
- Guest SSH Control
- Command Execution
- Box Types
- Error Types
- Metrics
- Type Definitions
- Constants
The main runtime for creating and managing boxes.
import { JsBoxlite } from 'boxlite';
// or use the wrapper classes
import { SimpleBox } from 'boxlite';new JsBoxlite(options: JsOptions)| Method | Signature | Description |
|---|---|---|
withDefaultConfig() |
() => JsBoxlite |
Get runtime with default config (~/.boxlite) |
initDefault() |
(options: JsOptions) => void |
Initialize default runtime with custom options |
| Method | Signature | Description |
|---|---|---|
create() |
(options: JsBoxOptions, name?: string) => Promise<JsBox> |
Create a new box |
listInfo() |
() => Promise<JsBoxInfo[]> |
List all boxes |
getInfo() |
(idOrName: string) => Promise<JsBoxInfo | null> |
Get box info |
get() |
(idOrName: string) => Promise<JsBox | null> |
Get box handle |
metrics() |
() => Promise<JsRuntimeMetrics> |
Get runtime metrics |
remove() |
(idOrName: string, force?: boolean) => Promise<void> |
Remove a box |
close() |
() => void |
Close runtime (no-op) |
images |
getter => ImageHandle |
The images this runtime can boot from; see ImageHandle |
registries |
getter => RegistryHandle |
The server's registry logins; throws unsupported on a local runtime. See RegistryHandle |
// Default runtime
const runtime = JsBoxlite.withDefaultConfig();
// Custom runtime
const runtime = new JsBoxlite({ homeDir: '/custom/path' });
// Create a box
const box = await runtime.create({
image: 'alpine:latest',
cpus: 2,
memoryMib: 512
}, 'my-box');
// List all boxes
const boxes = await runtime.listInfo();
boxes.forEach(info => console.log(`${info.id}: ${info.state.status}`));The images a runtime can boot from: the local cache on an embedded runtime,
the server catalog on a REST runtime. Registry credentials are accessed through
runtime.images.registries.
| Operation | Embedded runtime | REST runtime |
|---|---|---|
pull |
Pulls into the cache | Unsupported; creating a box pulls |
list |
One row per cached reference | Catalog alias and digest references |
get |
Cached versions under the name | Catalog versions, aliases and history |
remove |
Forgets the name; layers stay | Removes the entry; refused while a box can boot from it |
usage |
Unsupported | Image count, allowance and known bytes |
createAlias() |
Unsupported | Creates a new alias for a ready digest; existing names conflict |
deleteAlias() |
Unsupported | Removes only the named alias; absent names return NotFound |
get and remove take an image name, without a tag or digest, such as
quay.io/acme/app. Alias names use OCI tag syntax; creation takes the
sha256: digest of a ready version recorded for that image.
A registry tag belongs to the upstream registry. A BoxLite alias belongs to the runtime catalog and selects a recorded digest independently. A successful pull seeds an alias from the registry tag; it never overwrites an existing binding. Creating an alias never pushes a registry tag or pulls image bytes.
Alias creation refuses every existing name, even for the same digest, with
AlreadyExists. Delete the alias explicitly before creating it again. Deletion
removes only the binding: versions and existing boxes keep their digests.
Creation history remains available; deletion is recorded by the server audit log.
Image details and versions expose aliases. Their history contains
ImageAliasEvent records with alias, optional from_digest, to_digest,
optional actor and recorded_at. A local cache mirrors its cached registry
tags in aliases, leaves history empty and refuses alias writes.
const detail = await runtime.images.get('quay.io/acme/app');
await runtime.images.createAlias(detail.name, 'verified', detail.versions[0].digest);
await runtime.images.deleteAlias(detail.name, 'verified');
const logins = await runtime.images.registries.list();The JavaScript event fields use fromDigest, toDigest and recordedAt.
The logins a REST server presents when it pulls a private image for a box.
Read it from the runtime.images.registries getter, which throws unsupported on a
local runtime: that one pulls with the logins in imageRegistries instead.
| Method | Signature | Description |
|---|---|---|
list() |
() => Promise<RegistryCredential[]> |
Every login the organization holds, oldest first |
create() |
(credential: NewRegistryCredential) => Promise<RegistryCredential> |
Add a login; already_exists while one is held for the same registry and prefix |
remove() |
(id: string) => Promise<void> |
Remove a login; invalid_state, naming the boxes, while a box still pulls through it; not_found for an unknown id |
| Type | Fields |
|---|---|
NewRegistryCredential |
registryHost, repositoryPrefix (optional; whole path segments ending in /, omitted for the whole registry), username, password |
RegistryCredential |
id, registryHost, repositoryPrefix, username, createdBy (absent when unknown), createdAt (RFC 3339) |
The password goes up once and is never returned: RegistryCredential has no
password field. remove() rejects an id that is not a UUID with
invalid_argument, before any request.
const runtime = JsBoxlite.rest(new BoxliteRestOptions({ url: 'http://localhost:8100' }));
const login = await runtime.images.registries.create({
registryHost: 'ghcr.io',
repositoryPrefix: 'acme/',
username: 'acme-bot',
password: process.env.GHCR_TOKEN!,
});
const box = await runtime.create({ image: 'ghcr.io/acme/private-app:1' });
for (const entry of await runtime.images.registries.list()) {
console.log(entry.registryHost, entry.repositoryPrefix, entry.username);
}Runtime configuration options.
| Field | Type | Default | Description |
|---|---|---|---|
homeDir |
string |
~/.boxlite |
Base directory for runtime data |
imageRegistries |
JsImageRegistry[] |
[] |
Registry transport, TLS, search, and auth configuration |
Configuration options for creating a box.
| Field | Type | Default | Description |
|---|---|---|---|
image |
string |
- | OCI image URI |
rootfsPath |
string |
- | Pre-prepared rootfs directory (alternative to image) |
cpus |
number |
1 |
Number of CPU cores (1–16, the guest kernel's limit) |
memoryMib |
number |
512 |
Memory limit in MiB |
diskSizeGb |
number |
- | Container disk size in GB, never smaller than the image |
workingDir |
string |
"/root" |
Working directory inside container |
env |
JsEnvVar[] |
[] |
Environment variables |
volumes |
JsVolumeSpec[] |
[] |
Volume mounts |
network |
NetworkSpec |
{ mode: "enabled" } |
Structured network configuration |
ports |
JsPortSpec[] |
[] |
Local TCP port mappings; omit hostPort for automatic allocation |
secrets |
Secret[] |
[] |
Outbound HTTPS secret substitution rules |
advanced |
AdvancedBoxOptions |
{} |
Expert-only options, including capabilities.add and capabilities.drop |
autoDelete |
number |
- | 0 keeps the box after stop; above 0, a remote runtime deletes it that many seconds after stop and a local runtime at stop. Unset keeps the runtime's default: autoRemove locally, the server's policy on a remote runtime |
autoRemove |
boolean |
false |
Deprecated: use autoDelete. Auto cleanup when stopped |
detach |
boolean |
false |
Survive parent process exit |
Capability policy is intentionally nested with the other expert-only options:
const options = {
image: "alpine:latest",
advanced: {
capabilities: {
add: ["NET_BIND_SERVICE"],
drop: ["NET_RAW"],
},
},
};interface NetworkSpec {
mode: "enabled" | "disabled";
allowNet?: string[];
}Use allowNet only when mode: "enabled". Empty or omitted allowNet means full outbound access. A host matched by a configured secret is additionally reachable on port 443 without a rule of its own, so allowNet is not the only egress gate. The connection is dialed by name, and under a non-empty allowlist an answer in a private, loopback or CGNAT range is refused unless an IP or CIDR rule covers it. mode: "disabled" removes the guest network interface entirely.
interface JsEnvVar {
key: string;
value: string;
}A mount has exactly one origin — a managed volume or a host bind path:
type JsVolumeSpec =
| {
// The volume's server-assigned id or its name - the server resolves either.
managedVolume: string;
guestPath: string;
// Read-only managed mounts are not implemented yet; `true` is rejected.
readOnly?: false;
}
| {
hostPath: string; // Path on host
guestPath: string; // Path in container
readOnly?: boolean; // Default: false
};volumes: [
{ managedVolume: "my-data", guestPath: "/data" },
{ managedVolume: "vol_01K2EXAMPLE", guestPath: "/cache" },
];Setting both origins, or neither, is rejected. Host bind mounts are local-runtime only; a REST runtime refuses them.
interface JsPortSpec {
hostPort?: number; // None = auto-assign
guestPort: number; // Port inside container
protocol?: string; // "tcp" (UDP is rejected)
hostIp?: string; // Default: "0.0.0.0"
}Port publication is available only with a local runtime. For code that should
work with both local and remote runtimes, use box.network.tunnel(new SocketAddress({ port })); each
tunnel is one-shot; call forward() to consume it into a listener.
OCI EXPOSE declarations do not publish host ports.
interface Secret {
name: string;
value: string;
hosts?: string[];
placeholder?: string; // Default: `<BOXLITE_SECRET:${name}>`
}Handle to a running or stopped box.
| Property | Type | Description |
|---|---|---|
id |
string |
Unique box identifier (ULID) |
name |
string | null |
User-defined name |
network |
JsNetworkHandle |
Box-scoped tunnel operations |
ssh |
JsSshHandle |
Configure, query, or disable guest SSH |
| Method | Signature | Description |
|---|---|---|
info() |
() => Promise<JsBoxInfo> |
Get box metadata |
exec() |
(cmd, args?, env?, tty?) => Promise<JsExecution> |
Execute command |
stop() |
() => Promise<void> |
Stop the box |
metrics() |
() => Promise<JsBoxMetrics> |
Get resource metrics |
Metadata about a box.
| Field | Type | Description |
|---|---|---|
id |
string |
Unique box identifier (ULID) |
name |
string | undefined |
User-defined name |
state |
JsBoxStateInfo |
Runtime state with status, running, and optional pid and exitCode fields. exitCode is how the main command ended — its own code, or 128 + n when a signal ended it; stopping a box signals that command, so a stop is recorded here too; 0 is a real value, so test for undefined rather than falsiness |
createdAt |
string |
Creation timestamp (ISO 8601) |
startedAt |
string | undefined |
Time when the box most recently entered Running (RFC 3339); absent if not recorded or unavailable over REST |
lastActivityAt |
string | undefined |
Time the box was last active (RFC 3339), the clock AutoStop measures idleness against; absent for a local box, which records no activity |
image |
string |
OCI image reference or rootfs path |
cpus |
number |
Allocated CPU count |
memoryMib |
number |
Allocated memory in MiB |
network |
JsNetworkInfo | null |
Current network configuration and resolved local publications |
interface JsOutboundNetworkInfo {
// (JsInboundNetworkInfo has the same shape)
mode: string;
allowNet: string[];
}
interface JsNetworkInfo {
outbound: JsOutboundNetworkInfo;
inbound: JsInboundNetworkInfo;
publishedPorts: JsPublishedPort[] | null;
/** @deprecated Mirrors outbound.mode. */
mode: string;
/** @deprecated Mirrors outbound.allowNet. */
allowNet: string[];
}
interface JsPublishedPort {
guestPort: number;
hostIp: string;
hostPort: number;
protocol: string;
}network === null means network information is unavailable. Within
JsNetworkInfo, publishedPorts === null means the current handle does not know
the lifecycle's publications, [] means there are no active publications, and
a populated array contains concrete active local bindings. JsPortSpec remains
the request type; resolved output uses JsPublishedPort so every reported host
port is concrete.
box.info() always returns a promise. Local metadata reads report
bindings captured when this handle started or reattached the box; REST metadata
reads fetch the current server record. A newly loaded local running box has no
live binding data yet, so box, get, or list info may report
publishedPorts === null until an operation requiring live state reattaches it.
Create targets with new SocketAddress({ address: "127.0.0.1", port: 3000 })
from node:net; IPv6 also sets family: "ipv6". Flowlabel must be zero.
The old { type: "tcp", ... } target is rejected; that shape remains a listener
argument to forward().
JsBox and SimpleBox expose the same box.network workflow.
| Operation | Signature | Description |
|---|---|---|
| Tunnel | await box.network.tunnel(target, options?) |
Prepare a JsBoxTunnel or BoxTunnel; target is SocketAddress imported from node:net (loopback or the guest IP), options is { isPublic?: boolean }, public by default. Bare port and boolean arguments are rejected; invalid types throw synchronously on the native JsBox.network handle |
| Token | tunnel.token(): string | null |
Full on creation, masked on later preparations; isPublic() reports the mode |
| Revoke | await box.network.revokeTunnel(port) |
Withdraw the port's tunnel; open connections stay open |
| Forward | await tunnel.forward(listen) |
Return a listener-backed TunnelForwarder |
| Inspect | tunnel.uri(): string | null |
Read the prepared public URL; null for a local box |
| Connect | await tunnel.connect() |
Consume the prepared tunnel into its connection |
| Read/write | await connection.read(maxBytes), await connection.write(data) |
Exchange bytes with the service |
| Close | await connection.close() |
Close the connection |
listen is { type: "tcp", host?: string, port: number } or
{ type: "unix", path: string }. The forwarder exposes localAddr(), wait(),
and repeatable close().
Each tunnel is one-shot. Choose connect() or forward(); a forwarder opens
fresh connections against the prepared declaration without preparing again.
It cannot undo revocation. This differs from ports, which
creates a persistent, local-only host listener that accepts repeated
connections from ordinary host applications.
JsBox and SimpleBox expose box.ssh.
| Operation | Signature | Description |
|---|---|---|
| Configure | await box.ssh.configure(config) |
Apply SshConfig and return SshStatus |
| Observe | await box.ssh.status() |
Return SshStatus |
| Disable | await box.ssh.disable() |
Disable SSH and return SshStatus |
interface SshConfig {
listenAddress: string; // e.g. "0.0.0.0:2222"
hostPrivateKey: string; // unencrypted OpenSSH host private key
accounts: SshAccount[]; // non-empty; each has a key or a CA
}
interface SshAccount {
login: string; // 1-128 chars: [A-Za-z0-9._-]
authorizedKeys?: string[]; // OpenSSH public keys
ca?: SshCaConfig; // certificate authority alternative
}
interface SshCaConfig {
publicKey: string;
principal: string; // required certificate principal
}
interface SshStatus {
enabled: boolean;
generation: bigint; // full u64 precision
listenAddress: string;
hostPublicKey: string; // comment-free public host key
hostKeyFingerprint: string; // SHA-256 fingerprint
}On a SimpleBox, a first configure call lazily creates or fetches the box
before validating the configuration: a wrong-typed configuration can leave the
created box behind, but no SSH operation is sent for it. status and
disable never start the VM.
Invalid configuration field types report InvalidArg with the message
invalid SSH configuration, without echoing rejected values. Other errors
use the SDK's existing error types.
Handle for a running command.
| Method | Signature | Description |
|---|---|---|
id() |
() => Promise<string> |
Get execution ID |
stdin() |
() => Promise<JsExecStdin> |
Get stdin writer |
stdout() |
() => Promise<JsExecStdout> |
Get stdout reader |
stderr() |
() => Promise<JsExecStderr> |
Get stderr reader |
wait() |
() => Promise<JsExecResult> |
Wait for completion |
kill() |
() => Promise<void> |
Send SIGKILL |
const execution = await box.exec('ls', ['-la', '/']);
// Read stdout
const stdout = await execution.stdout();
while (true) {
const line = await stdout.next();
if (line === null) break;
console.log(line);
}
// Wait for completion
const result = await execution.wait();
console.log(`Exit code: ${result.exitCode}`);Writer for sending input to a running process.
| Method | Signature | Description |
|---|---|---|
write() |
(data: Buffer) => Promise<void> |
Write bytes |
writeString() |
(text: string) => Promise<void> |
Write UTF-8 string |
const stdin = await execution.stdin();
await stdin.writeString('Hello, World!\n');
await stdin.write(Buffer.from([10])); // newlineReaders for streaming output.
| Method | Signature | Description |
|---|---|---|
next() |
() => Promise<string | null> |
Read next line (null = EOF) |
Stream Consumption: Each stream can only be consumed once. After iterating to EOF, subsequent calls return null.
const stdout = await execution.stdout();
while (true) {
const line = await stdout.next();
if (line === null) break;
console.log(line);
}Result of a completed execution.
| Field | Type | Description |
|---|---|---|
exitCode |
number |
Process exit code (0 = success) |
Context manager for basic command execution with automatic cleanup.
import { SimpleBox } from 'boxlite';interface SimpleBoxOptions {
image?: string; // Default: "python:slim"
memoryMib?: number; // Memory in MiB
cpus?: number; // CPU cores
runtime?: JsBoxlite; // Runtime instance
name?: string; // Box name
autoRemove?: boolean; // Default: true
detach?: boolean; // Default: false
workingDir?: string; // Working directory
env?: Record<string, string>; // Environment variables
volumes?: JsVolumeSpec[]; // Volume mounts (managedVolume or hostPath)
network?: NetworkSpec;
ports?: PortSpec[]; // Port mappings
secrets?: Secret[];
advanced?: {
capabilities?: {
add?: string[]; // Add Linux capabilities
drop?: string[]; // Remove Linux capabilities
};
};
}| Property | Type | Description |
|---|---|---|
id |
string |
Box ID (throws if not started) |
name |
string | undefined |
Box name |
| Method | Signature | Description |
|---|---|---|
getId() |
() => Promise<string> |
Get box ID (async) |
getInfo() |
() => Promise<JsBoxInfo> |
Get box info (async) |
exec() |
(cmd, ...args) => Promise<ExecResult> |
Execute and wait (variadic) |
exec() |
(cmd, args[], env?, options?) => Promise<ExecResult> |
Execute with options (array form) |
stop() |
() => Promise<void> |
Stop the box |
[Symbol.asyncDispose]() |
() => Promise<void> |
Async disposal |
// With async disposal (TypeScript 5.2+)
await using box = new SimpleBox({ image: 'alpine:latest' });
const result = await box.exec('echo', 'Hello!');
console.log(result.stdout);
// Manual cleanup
const box = new SimpleBox({ image: 'alpine:latest' });
try {
const result = await box.exec('ls', '-la');
console.log(result.stdout);
// Per-command options (array form)
const pwd = await box.exec('pwd', [], undefined, { cwd: '/tmp' });
const who = await box.exec('whoami', [], undefined, { user: 'nobody' });
const timed = await box.exec('sleep', ['60'], undefined, { timeoutSecs: 5 });
} finally {
await box.stop();
}The options parameter accepts { cwd?: string; user?: string; timeoutSecs?: number }.
Python code execution sandbox.
import { CodeBox } from 'boxlite';interface CodeBoxOptions extends SimpleBoxOptions {
image?: string; // Default: "python:slim"
}| Method | Signature | Description |
|---|---|---|
run() |
(code: string) => Promise<string> |
Execute Python code |
runScript() |
(scriptPath: string) => Promise<string> |
Run script file |
installPackage() |
(pkg: string) => Promise<string> |
pip install |
installPackages() |
(...pkgs: string[]) => Promise<string> |
Install multiple |
const codebox = new CodeBox({ memoryMib: 1024 });
try {
await codebox.installPackage('requests');
const result = await codebox.run(`
import requests
print(requests.get('https://api.github.com/zen').text)
`);
console.log(result);
} finally {
await codebox.stop();
}Browser automation with Chrome DevTools Protocol.
import { BrowserBox, BrowserType } from 'boxlite';interface BrowserBoxOptions {
browser?: BrowserType; // "chromium" | "firefox" | "webkit"
memoryMib?: number; // Default: 2048
cpus?: number; // Default: 2
}| Browser | Port | Image |
|---|---|---|
chromium |
9222 | mcr.microsoft.com/playwright:v1.47.2-jammy |
firefox |
9223 | browserless/firefox:latest |
webkit |
9224 | browserless/webkit:latest |
| Method | Signature | Description |
|---|---|---|
start() |
(timeout?: number) => Promise<void> |
Start browser |
endpoint() |
() => string |
Get CDP endpoint URL |
import puppeteer from 'puppeteer-core';
const browser = new BrowserBox({ browser: 'chromium' });
try {
await browser.start();
const endpoint = browser.endpoint(); // "http://localhost:9222"
const instance = await puppeteer.connect({ browserURL: endpoint });
const page = await instance.newPage();
await page.goto('https://example.com');
console.log(await page.title());
} finally {
await browser.stop();
}Desktop automation with full GUI environment.
import { ComputerBox } from 'boxlite';interface ComputerBoxOptions {
cpus?: number; // Default: 2
memoryMib?: number; // Default: 2048
guiHttpPort?: number; // Default: 3000
guiHttpsPort?: number; // Default: 3001
}| Method | Signature | Description |
|---|---|---|
mouseMove() |
(x: number, y: number) => Promise<void> |
Move cursor |
leftClick() |
() => Promise<void> |
Left click |
rightClick() |
() => Promise<void> |
Right click |
middleClick() |
() => Promise<void> |
Middle click |
doubleClick() |
() => Promise<void> |
Double click |
tripleClick() |
() => Promise<void> |
Triple click |
leftClickDrag() |
(startX, startY, endX, endY) => Promise<void> |
Drag |
cursorPosition() |
() => Promise<[number, number]> |
Get cursor pos |
| Method | Signature | Description |
|---|---|---|
type() |
(text: string) => Promise<void> |
Type text |
key() |
(keySequence: string) => Promise<void> |
Press key(s) |
| Key | Syntax |
|---|---|
| Enter | Return |
| Tab | Tab |
| Escape | Escape |
| Backspace | BackSpace |
| Delete | Delete |
| Space | space |
| Arrow keys | Up, Down, Left, Right |
| Function keys | F1, F2, ... F12 |
| Page keys | Page_Up, Page_Down, Home, End |
| Modifiers | ctrl, alt, shift, super |
| Combinations | ctrl+c, ctrl+shift+s, alt+Tab |
Examples:
await desktop.key('Return'); // Press Enter
await desktop.key('ctrl+c'); // Copy
await desktop.key('ctrl+shift+s'); // Save As
await desktop.key('alt+Tab'); // Switch window
await desktop.key('ctrl+a Delete'); // Select all and delete| Method | Signature | Description |
|---|---|---|
waitUntilReady() |
(timeout?: number) => Promise<void> |
Wait for desktop |
screenshot() |
() => Promise<Screenshot> |
Capture screen |
scroll() |
(x, y, direction, amount?) => Promise<void> |
Scroll |
getScreenSize() |
() => Promise<[number, number]> |
Get dimensions |
interface Screenshot {
data: string; // Base64-encoded PNG
width: number; // 1024 (default)
height: number; // 768 (default)
format: 'png';
}| Direction | Description |
|---|---|
"up" |
Scroll up |
"down" |
Scroll down |
"left" |
Scroll left |
"right" |
Scroll right |
const desktop = new ComputerBox({ cpus: 4, memoryMib: 4096 });
try {
await desktop.waitUntilReady(60);
// Take screenshot
const screenshot = await desktop.screenshot();
console.log(`${screenshot.width}x${screenshot.height}`);
// GUI interaction
await desktop.mouseMove(100, 200);
await desktop.leftClick();
await desktop.type('Hello, World!');
await desktop.key('Return');
// Access via browser: http://localhost:3000
} finally {
await desktop.stop();
}Interactive terminal sessions with PTY support.
import { InteractiveBox } from 'boxlite';interface InteractiveBoxOptions extends SimpleBoxOptions {
shell?: string; // Default: "/bin/sh"
tty?: boolean; // undefined = auto-detect
}| Value | Behavior |
|---|---|
undefined |
Auto-detect from stdin |
true |
Force TTY with I/O forwarding |
false |
No I/O forwarding |
| Method | Signature | Description |
|---|---|---|
start() |
() => Promise<void> |
Start PTY session |
wait() |
() => Promise<void> |
Wait for shell exit |
const box = new InteractiveBox({
image: 'alpine:latest',
shell: '/bin/sh',
tty: true
});
try {
await box.start();
await box.wait(); // Blocks until shell exits
} finally {
await box.stop();
}import { BoxliteError, ExecError, TimeoutError, ParseError } from 'boxlite';BoxliteError (base)
├── ExecError # Command failed
├── TimeoutError # Operation timeout
└── ParseError # Output parsing failed
Base error class for all BoxLite errors.
try {
await box.exec('invalid-command');
} catch (err) {
if (err instanceof BoxliteError) {
console.error('BoxLite error:', err.message);
}
}Command execution failed (non-zero exit code).
| Property | Type | Description |
|---|---|---|
command |
string |
Failed command |
exitCode |
number |
Non-zero exit code |
stderr |
string |
Standard error output |
try {
await box.exec('false');
} catch (err) {
if (err instanceof ExecError) {
console.error(`Command: ${err.command}`);
console.error(`Exit code: ${err.exitCode}`);
console.error(`Stderr: ${err.stderr}`);
}
}Operation exceeded time limit.
try {
await desktop.waitUntilReady(5);
} catch (err) {
if (err instanceof TimeoutError) {
console.error('Desktop did not become ready');
}
}Failed to parse command output.
try {
const pos = await desktop.cursorPosition();
} catch (err) {
if (err instanceof ParseError) {
console.error('Failed to parse cursor position');
}
}A failure the native runtime reports is a plain Error whose message starts
with the kind of failure. errorCode returns that kind's code, or undefined
for any other error. The codes are the ones BoxliteError::http() gives
(src/shared/src/errors.rs) and a REST server answers with, and the same as
the code of Python's runtime failure classes.
import { errorCode } from 'boxlite';
try {
await runtime.remove('no-such-box');
} catch (err) {
if (errorCode(err) === 'not_found') {
// nothing to remove
}
}Runtime-wide metrics.
| Field | Type | Description |
|---|---|---|
boxesCreatedTotal |
number |
Total boxes created |
boxesFailedTotal |
number |
Boxes that failed during creation |
numRunningBoxes |
number |
Currently running boxes |
totalCommandsExecuted |
number |
Total commands executed |
totalExecErrors |
number |
Total execution errors |
const metrics = await runtime.metrics();
console.log(`Boxes created: ${metrics.boxesCreatedTotal}`);
console.log(`Running: ${metrics.numRunningBoxes}`);Per-box resource metrics.
| Field | Type | Description |
|---|---|---|
commandsExecutedTotal |
number |
Commands executed on this box |
execErrorsTotal |
number |
Execution errors on this box |
bytesSentTotal |
number |
Bytes sent via stdin |
bytesReceivedTotal |
number |
Bytes received via stdout/stderr |
| Field | Type | Description |
|---|---|---|
cpuPercent |
number | undefined |
CPU usage (0.0-100.0) |
memoryBytes |
number | undefined |
Memory usage in bytes |
networkBytesSent |
number | undefined |
Network bytes sent |
networkBytesReceived |
number | undefined |
Network bytes received |
networkTcpConnections |
number | undefined |
Current TCP connections |
networkTcpErrors |
number | undefined |
Total TCP errors |
| Field | Type | Description |
|---|---|---|
totalCreateDurationMs |
number | undefined |
Total create time |
guestBootDurationMs |
number | undefined |
Guest agent ready time |
stageFilesystemSetupMs |
number | undefined |
Directory setup time |
stageImagePrepareMs |
number | undefined |
Image pull/prepare time |
stageGuestRootfsMs |
number | undefined |
Rootfs bootstrap time |
stageBoxConfigMs |
number | undefined |
Configuration build time |
stageBoxSpawnMs |
number | undefined |
Subprocess spawn time |
stageContainerInitMs |
number | undefined |
Container init time |
const metrics = await box.metrics();
console.log(`CPU: ${metrics.cpuPercent}%`);
console.log(`Memory: ${(metrics.memoryBytes || 0) / (1024 * 1024)} MB`);
console.log(`Boot time: ${metrics.guestBootDurationMs}ms`);Result from SimpleBox.exec().
interface ExecResult {
exitCode: number;
stdout: string;
stderr: string;
}Screenshot capture result.
interface Screenshot {
data: string; // Base64-encoded PNG
width: number;
height: number;
format: 'png';
}Supported browser types.
type BrowserType = 'chromium' | 'firefox' | 'webkit';Default values used by BoxLite.
| Constant | Value | Description |
|---|---|---|
DEFAULT_CPUS |
1 |
Default CPU cores |
DEFAULT_MEMORY_MIB |
512 |
Default memory in MiB |
| Constant | Value | Description |
|---|---|---|
COMPUTERBOX_CPUS |
2 |
Default CPUs |
COMPUTERBOX_MEMORY_MIB |
2048 |
Default memory |
COMPUTERBOX_DISPLAY_WIDTH |
1024 |
Screen width |
COMPUTERBOX_DISPLAY_HEIGHT |
768 |
Screen height |
COMPUTERBOX_GUI_HTTP_PORT |
3000 |
HTTP GUI port |
COMPUTERBOX_GUI_HTTPS_PORT |
3001 |
HTTPS GUI port |
DESKTOP_READY_TIMEOUT |
60 |
Ready timeout (seconds) |
| Constant | Value | Description |
|---|---|---|
BROWSERBOX_PORT_CHROMIUM |
9222 |
Chromium CDP port |
BROWSERBOX_PORT_FIREFOX |
9223 |
Firefox CDP port |
BROWSERBOX_PORT_WEBKIT |
9224 |
WebKit CDP port |
- Node.js SDK README - Quick start and examples
- Getting Started Guide - Installation
- Configuration Reference - BoxOptions details
- Error Codes - Error handling