Install
The package ships the devsandbox binary for your platform next to the typed API, so one dependency covers both.
npm i devsandboxesUsage
import { spawn } from 'node:child_process';
import * as devsandbox from 'devsandboxes';
const { name, worktree } = await devsandbox.run('web', { dir: './sandboxes', stderr: 'inherit' });
const { instances } = await devsandbox.status({ dir: './sandboxes' });
for (const i of instances) console.log(i.name, i.status.state, i.drift);
const { exitCode, stdout } = await devsandbox.exec(name, ['git', 'status']);
// Your own process or pty (node-pty takes the same file/args): a login shell.
const { file, args } = devsandbox.execArgv(name, [], { interactive: true, tty: true });
spawn(file, args, { stdio: 'inherit' });
await devsandbox.rm(name, { deleteBranch: true });Every function takes { dir, cwd, env, signal, stderr }, except the synchronous binaryPath() and execArgv(), and connect() (below). dir is the config root (-C). A failed command rejects with DevsandboxError (exitCode, stdout, stderr).
At a glance
| Function | Resolves to | Description |
|---|---|---|
binaryPath() | stringsync | Absolute path of the native binary for this platform (DEVSANDBOX_BINARY overrides) |
cli() | CliResult | Run the CLI with raw arguments |
ls() | SandboxRow[] | Sandbox configs in devsandboxes.toml |
ps() | ContainerRow[] | Running devsandbox containers (all includes stopped ones) |
stats() | StatsRow[] | CPU/memory of running devsandbox containers |
status() | Snapshot | Sandboxes, instances, and services in one snapshot |
inspect() | T | The runtime's own inspect document (docker/podman: an array of containers) |
run() | RunRecord | Create and start an instance of sandbox |
start() | void | — |
stop() | void | — |
rebuild() | void | Recreate from current config when drifted (force: even without drift) |
rename() | void | — |
done() | void | Mark an instance done: kept as is (container, worktree), shown dimmed until removed |
undone() | void | Clear an instance's done mark |
rm() | void | Remove container, worktree, and state entry |
gc() | void | Remove unreferenced services (force: also orphaned shell-history files) |
logs() | string | Last lines (default 50) lines of a container's merged stdout/stderr |
exec() | CliResult | Run command in an instance |
execArgv() | ExecInvocationsync | Argv for running cmd in an instance under your own process or pty (node-pty, child_process.spawn) |
service.ls() | ServiceRow[] | — |
service.rebuild() | void | Recreate a service's containers and rewire running sandboxes in place |
connect() | Api | Connect to the host daemon through devsandbox api --stdio, starting the daemon if needed, and say hello |
Functions
Named exports of devsandboxes. Everything but binaryPath() and execArgv() runs the CLI and returns a promise.
binaryPath()function
Absolute path of the native binary for this platform (DEVSANDBOX_BINARY overrides).
function binaryPath(): stringcli()function
Run the CLI with raw arguments.
function cli(args: readonly string[], opts?: CliOptions): Promise<CliResult>function cli(
args: readonly string[],
opts?: CliOptions,
): Promise<CliResult>| Parameter | Type |
|---|---|
args | readonly string[] |
optsoptional | CliOptions |
ls()function
Sandbox configs in devsandboxes.toml.
function ls(opts?: CommonOptions): Promise<SandboxRow[]>function ls(
opts?: CommonOptions,
): Promise<SandboxRow[]>| Parameter | Type |
|---|---|
optsoptional | CommonOptions |
ps()function
Running devsandbox containers (all includes stopped ones).
function ps(opts?: CommonOptions & { all?: boolean }): Promise<ContainerRow[]>function ps(
opts?: CommonOptions & { all?: boolean },
): Promise<ContainerRow[]>| Parameter | Type | Description |
|---|---|---|
optsoptional | CommonOptions & { all?: boolean } | Every option of |
opts.alloptional | boolean | — |
stats()function
CPU/memory of running devsandbox containers.
function stats(opts?: CommonOptions): Promise<StatsRow[]>function stats(
opts?: CommonOptions,
): Promise<StatsRow[]>| Parameter | Type |
|---|---|
optsoptional | CommonOptions |
status()function
Sandboxes, instances, and services in one snapshot.
function status(opts?: CommonOptions): Promise<Snapshot>function status(
opts?: CommonOptions,
): Promise<Snapshot>| Parameter | Type |
|---|---|
optsoptional | CommonOptions |
inspect()function
The runtime's own inspect document (docker/podman: an array of containers).
function inspect<T = unknown>(name: string, opts?: CommonOptions): Promise<T>function inspect<T = unknown>(
name: string,
opts?: CommonOptions,
): Promise<T>| Parameter | Type |
|---|---|
name | string |
optsoptional | CommonOptions |
run()function
Create and start an instance of sandbox; resolves with where it lives.
function run(sandbox: string, opts?: RunOptions): Promise<RunRecord>function run(
sandbox: string,
opts?: RunOptions,
): Promise<RunRecord>| Parameter | Type |
|---|---|
sandbox | string |
optsoptional | RunOptions |
start()function
function start(target: Target, opts?: CommonOptions): Promise<void>function start(
target: Target,
opts?: CommonOptions,
): Promise<void>| Parameter | Type |
|---|---|
target | Target |
optsoptional | CommonOptions |
stop()function
function stop(target: Target, opts?: CommonOptions): Promise<void>function stop(
target: Target,
opts?: CommonOptions,
): Promise<void>| Parameter | Type |
|---|---|
target | Target |
optsoptional | CommonOptions |
rebuild()function
Recreate from current config when drifted (force: even without drift).
function rebuild(
target: Target,
opts?: CommonOptions & { force?: boolean },
): Promise<void>| Parameter | Type | Description |
|---|---|---|
target | Target | — |
optsoptional | CommonOptions & { force?: boolean } | Every option of |
opts.forceoptional | boolean | — |
rename()function
function rename(name: string, newName: string, opts?: CommonOptions): Promise<void>function rename(
name: string,
newName: string,
opts?: CommonOptions,
): Promise<void>| Parameter | Type |
|---|---|
name | string |
newName | string |
optsoptional | CommonOptions |
done()function
Mark an instance done: kept as is (container, worktree), shown dimmed until removed.
function done(name: string, opts?: CommonOptions): Promise<void>function done(
name: string,
opts?: CommonOptions,
): Promise<void>| Parameter | Type |
|---|---|
name | string |
optsoptional | CommonOptions |
undone()function
Clear an instance's done mark.
function undone(name: string, opts?: CommonOptions): Promise<void>function undone(
name: string,
opts?: CommonOptions,
): Promise<void>| Parameter | Type |
|---|---|
name | string |
optsoptional | CommonOptions |
rm()function
Remove container, worktree, and state entry. Rejects, removing nothing, when the worktree has uncommitted or untracked changes, unless force.
function rm(
name: string,
opts?: CommonOptions & { /** * The worktree branch `run` created: `true` deletes it (`git branch -D`, * unmerged commits too), `false` or omitted keeps it. Branches `run` * reused are always kept. */ deleteBranch?: boolean; /** * Remove anyway: uncommitted or untracked worktree changes are * discarded, and a failed step (logged on stderr) is skipped so the * instance still leaves state; what failed stays on disk. */ force?: boolean; },
): Promise<void>| Parameter | Type | Description |
|---|---|---|
name | string | — |
optsoptional | CommonOptions & { /** * The worktree branch `run` created: `true` deletes it (`git branch -D`, * unmerged commits too), `false` or omitted keeps it. Branches `run` * reused are always kept. */ deleteBranch?: boolean; /** * Remove anyway: uncommitted or untracked worktree changes are * discarded, and a failed step (logged on stderr) is skipped so the * instance still leaves state; what failed stays on disk. */ force?: boolean; } | Every option of |
opts.deleteBranchoptional | boolean | The worktree branch |
opts.forceoptional | boolean | Remove anyway: uncommitted or untracked worktree changes are discarded, and a failed step (logged on stderr) is skipped so the instance still leaves state; what failed stays on disk. |
gc()function
Remove unreferenced services (force: also orphaned shell-history files).
function gc(opts?: CommonOptions & { force?: boolean }): Promise<void>function gc(
opts?: CommonOptions & { force?: boolean },
): Promise<void>| Parameter | Type | Description |
|---|---|---|
optsoptional | CommonOptions & { force?: boolean } | Every option of |
opts.forceoptional | boolean | — |
logs()function
Last lines (default 50) lines of a container's merged stdout/stderr.
function logs(
name: string,
opts?: CommonOptions & { lines?: number },
): Promise<string>| Parameter | Type | Description |
|---|---|---|
name | string | — |
optsoptional | CommonOptions & { lines?: number } | Every option of |
opts.linesoptional | number | — |
exec()function
Run command in an instance. Resolves with its exit code rather than rejecting on non-zero.
function exec(
name: string,
command: readonly string[],
opts?: ExecOptions,
): Promise<CliResult>| Parameter | Type |
|---|---|
name | string |
command | readonly string[] |
optsoptional | ExecOptions |
execArgv()function
Argv for running cmd in an instance under your own process or pty (node-pty, child_process.spawn). Without cmd, a login shell (zsh, bash, or sh). With neither flag set the CLI picks: -i, plus -t when its stdin is a TTY (as under a pty); setting either passes exactly what you set, so set both for an interactive shell.
function execArgv(
name: string,
cmd?: readonly string[],
opts?: ExecArgvOptions,
): ExecInvocation| Parameter | Type |
|---|---|
name | string |
cmdoptional | readonly string[] |
optsoptional | ExecArgvOptions |
connect()function
Connect to the host daemon through devsandbox api --stdio, starting the daemon if needed, and say hello. Rejects with DevsandboxApiError: unsupported on Windows (the daemon is unix only), protocol when the daemon speaks another protocol, closed when the relay exits first.
function connect(opts?: ConnectOptions): Promise<Api>function connect(
opts?: ConnectOptions,
): Promise<Api>| Parameter | Type |
|---|---|
optsoptional | ConnectOptions |
service
Methods of the exported service object: devsandbox.service.ls().
service.ls()method
ls(opts?: CommonOptions): Promise<ServiceRow[]>ls(
opts?: CommonOptions,
): Promise<ServiceRow[]>| Parameter | Type |
|---|---|
optsoptional | CommonOptions |
service.rebuild()method
Recreate a service's containers and rewire running sandboxes in place.
rebuild(name: string, opts?: CommonOptions): Promise<void>rebuild(
name: string,
opts?: CommonOptions,
): Promise<void>| Parameter | Type |
|---|---|
name | string |
optsoptional | CommonOptions |
Types
Payloads mirror the CLI's --json output field for field: names stay snake_case and a Rust Option<T> arrives asT | null.
Payloads
ContainerStatustype
Container liveness; text is the runtime's raw status (e.g. "Up 3 minutes"). unknown: the runtime wasn't asked (instances.list with depth: 'disk'); never in status().
type ContainerStatus =
| { state: 'running'; text: string }
| { state: 'exited'; text: string }
| { state: 'missing' }
| { state: 'unknown' };PhaseRowtype
Where an instance's creation stands while it isn't ready. step is preparing, building, creating or a lifecycle step's name (postCreateCommand, …); a failed one is kept until rebuild retries it or rm removes it (error is interrupted when its process died).
type PhaseRow =
| { state: 'in-flight'; step: string }
| { state: 'failed'; step: string; error: string };InstanceRowinterface
One instance (status().instances).
| Property | Type | Description |
|---|---|---|
name | string | — |
sandbox | string | — |
container | string | — |
status | ContainerStatus | — |
uptime_secs | number | — |
cpu | string | null | — |
mem | string | null | — |
folder | string | — |
worktree | boolean | — |
services | string[] | — |
workspace | string | — |
remote_user | string | null | — |
remote_env_len | number | — |
base_folder | string | — |
drift | boolean | Container no longer matches the current config/dockerfile; |
done | boolean | Marked done ( |
phaseoptional | PhaseRow | Still being created, or failed; absent once ready. Shown instead of |
root | string | null | The config root it was made from; |
machineoptional | string | The machine it's on, in a federated snapshot ( |
SandboxRowinterface
One [sandbox.*] from devsandboxes.toml (ls(), status().sandboxes).
| Property | Type | Description |
|---|---|---|
name | string | — |
source | string |
|
folder | string | null | — |
services | string[] | — |
extends | string[] |
|
config_hash | string | — |
build_hash | string | — |
issues | string[] | Config-validation problems (folder / mount resolution). |
dispatcher | boolean | Has a |
worktree_branch | string | null | The resolved |
root | string | null | The config root it was read from. |
machineoptional | string | As |
ServiceRowinterface
One [services.*] from devsandboxes.toml (service.ls(), status().services).
| Property | Type | Description |
|---|---|---|
name | string | — |
scope | 'global' | 'isolated' | — |
source | string | — |
ports | string[] | — |
containers | Array<[string, ContainerStatus]> | Backing containers as |
used_by | string[] | Instances whose sandbox references this service. |
env_len | number | — |
command | string | null | — |
config_hash | string | — |
drift | boolean | — |
root | string | null | The config root it was read from. |
machineoptional | string | As |
Snapshotinterface
Full snapshot (status()), the same data the TUI renders.
| Property | Type | Description |
|---|---|---|
instances | InstanceRow[] | — |
sandboxes | SandboxRow[] | — |
services | ServiceRow[] | — |
sandbox_count | number | — |
runtime_name | 'docker' | 'podman' | 'container' | — |
runtime_version | string | null | — |
error | string | null | Collection problem (e.g. runtime down); rows still come from local state. |
SnapshotDepthtype
How much of the runtime instances.list asks: full (the default) adds cpu/mem.
type SnapshotDepth = 'disk' | 'listing' | 'full';InstancesListinterface
instances.list: the Snapshot plus the dispatchers' children.
| Property | Type | Description |
|---|---|---|
thread_children | Record<string, Record<string, string>> | Dispatcher |
InstancesSnapshotinterface
instances.snapshot: a watched root's InstancesList, pushed on every poll (about every 2 s; cpu/mem refreshed at most every 7 s and carried over in between), so its arrival says how fresh it is.
| Property | Type | Description |
|---|---|---|
dir | string | The config root, as |
machinesoptional | SnapshotMachine[] | With |
LinkStatetype
Where a machine's link stands. idle: not wanted, so not connected.
type LinkState = 'idle' | 'connecting' | 'connected' | 'unreachable';SnapshotMachineinterface
One machine of a federated InstancesSnapshot.
| Property | Type | Description |
|---|---|---|
name | string | — |
target | string | What ssh takes, or an |
state | LinkState | — |
error | string | null | Why it's |
version | string | null | Its devsandbox semver, once reached. |
runtime | string | null | Its runtime ( |
command | string | null | The remote devsandbox as shell text; |
agent | boolean | This host's ssh-agent is relayed to it ( |
RunRecordinterface
The instance run() just created (run --json). Fields match InstanceRow where they overlap, except worktree, which is the path.
| Property | Type | Description |
|---|---|---|
name | string | Instance name; what every |
instance_id | string | Persistent id; differs from |
sandbox | string | — |
container | string | — |
workspace | string | Workspace folder inside the container. |
folder | string | Host folder mounted as the workspace (the worktree for a worktree instance). |
base_folder | string | Host base repo folder the instance derives from. |
worktree | string | null | Host worktree path; |
branch | string | null | Worktree branch; |
ContainerRowinterface
One container from the runtime listing (ps()).
| Property | Type | Description |
|---|---|---|
name | string | — |
image | string | — |
status | string | Human status ( |
state | string |
|
labels | Record<string, string> | — |
host_ports | string[] | — |
done | boolean | The container's instance is marked done ( |
phaseoptional | PhaseRow | The container's instance is still being created, or failed; absent once ready. |
StatsRowinterface
Resource usage of one running container (stats()), pre-rendered.
| Property | Type |
|---|---|
name | string |
cpu | string |
mem | string |
Options & results
CommonOptionsinterface
| Property | Type | Description |
|---|---|---|
diroptional | string | Config root containing devsandboxes.toml (the CLI's |
cwdoptional | string | — |
envoptional | NodeJS.ProcessEnv | — |
signaloptional | AbortSignal | — |
stderroptional | 'pipe' | 'inherit' |
|
CliOptionsinterface
| Property | Type | Description |
|---|---|---|
inputoptional | string | Buffer | Written to the process's stdin; stdin is closed otherwise. |
rejectoptional | boolean | Reject with |
CliResultinterface
| Property | Type | Description |
|---|---|---|
exitCode | number | null | — |
signal | NodeJS.Signals | null | — |
stdout | string | — |
stderr | string | Empty when |
Targettype
An instance name (or sandbox / folder name), or every instance.
type Target = string | { all: true };API
RunOptionsinterface
| Property | Type | Description |
|---|---|---|
nameoptional | string | Instance name; generated when omitted. |
branchoptional | string | Worktree branch (supports |
baseoptional | string | Start point for the worktree branch, e.g. |
ExecOptionsinterface
| Property | Type | Description |
|---|---|---|
inputoptional | string | Buffer | Piped to the command's stdin (passes |
ExecArgvOptionsinterface
| Property | Type | Description |
|---|---|---|
ttyoptional | boolean | Pass |
interactiveoptional | boolean | Pass |
ExecInvocationinterface
A spawnable devsandbox exec invocation: spawn(file, args), no shell quoting.
| Property | Type | Description |
|---|---|---|
file | string | The native binary, as |
args | string[] | — |
Daemon API
HelloParamsinterface
hello params: what connect() sends first.
| Property | Type | Description |
|---|---|---|
version | string | The client's devsandbox version; |
build | number | Unix mtime of a dev build; 0 otherwise. |
client | string | Who's calling ( |
HelloResultinterface
The daemon's answer to hello (api.daemon).
| Property | Type | Description |
|---|---|---|
version | string | — |
build | number | — |
protocol | number | The API protocol number; see |
handoffoptional | boolean | The client is newer: the daemon is exiting. |
ApiErrorBodyinterface
An error response's body: code is stable, message is for humans.
| Property | Type | Description |
|---|---|---|
code | string | — |
message | string | — |
dataoptional | unknown | Details some codes carry: |
OkResultinterface
What a mutation answers.
| Property | Type |
|---|---|
ok | true |
ThreadStatetype
A thread state; needs-you is waiting on the user.
type ThreadState = 'needs-you' | 'active' | 'done';InboxViewtype
An inbox.threads.list view, as in the dashboard.
type InboxView = 'needs-you' | 'active' | 'done' | 'all';ApiTopictype
A notification topic for subscribe.
type ApiTopic = 'inbox' | 'instances' | 'forwards';ThreadSummaryinterface
One Inbox thread (inbox.list()), and the head of ThreadDetail.
| Property | Type | Description |
|---|---|---|
id | number | Store id, stable for the thread's life: what |
owner | string | Owner's |
owner_name | string | Owner's instance name when it last wrote. |
key | string | null | Thread key; |
kind | 'thread' | 'notify' |
|
state | ThreadState | null |
|
status | string | null | The owner's status line. |
title | string | A thread's title; a notification's newest message, first line. |
level | 'info' | 'warn' | 'error' | null | A notification's newest level. |
unread | boolean | — |
archived | boolean | The owner was removed: read-only history. |
needs_you | boolean | In the |
changed_at | number | Unix seconds of the last change. |
ThreadDetailinterface
A thread with everything the dashboard's pane shows (inbox.get()).
| Property | Type | Description |
|---|---|---|
link | string | null |
|
child | string | null | The key, among the owner's dispatcher children, of the child it's about; |
compose | ThreadCompose | null | Set when the thread takes replies ( |
actions | ThreadAction[] | — |
feed | FeedItem[] | An owner thread's feed, oldest first (first-insert order). |
notes | ThreadNote[] | A notification's records, newest first. |
events_pending | number | Events the owner hasn't acked yet. |
ThreadComposeinterface
How a thread takes free-text replies.
| Property | Type | Description |
|---|---|---|
placeholder | string | null | — |
hint | string | null | What sending does now, shown under the box. |
ThreadActioninterface
An owner's action button (inbox.act()).
| Property | Type | Description |
|---|---|---|
id | string | — |
label | string | — |
done | boolean | Pressing it also sets the thread done. |
host | 'vscode' | 'terminal' | 'logs' | 'forward' | 'open' | 'rm' | null | The host verb it runs in the client that shows it; the API runs none. |
sends_event | boolean |
|
FeedItemtype
One item of a thread's feed, by type.
type FeedItem = FeedMessage | FeedReply | FeedAction | FeedSubmission | FeedMarker;FeedItemBaseinterface
What every feed item carries.
| Property | Type | Description |
|---|---|---|
seq | number | Arrival order across the whole Inbox. |
at | number | Unix seconds of first insert. |
FeedMessageinterface
A message from the thread's owner.
| Property | Type | Description |
|---|---|---|
type | 'message' | — |
id | string | The owner's id for it, unique in the thread. |
blocks | MessageBlock[] | — |
edited | boolean | Replaced in place since it was first sent. |
withdrawn | boolean | The owner took it back. |
FeedReplyinterface
The user's reply (inbox.reply()).
| Property | Type |
|---|---|
type | 'reply' |
text | string |
FeedActioninterface
The user pressed an action (inbox.act()).
| Property | Type | Description |
|---|---|---|
type | 'action' | — |
action | string | The action's id. |
label | string | Its label when pressed. |
FeedSubmissioninterface
The user submitted a form (inbox.form.submit).
| Property | Type | Description |
|---|---|---|
type | 'submission' | — |
message | string | The message holding the form. |
form | string | The form's id. |
answers | Record<string, FormAnswer | null> | Every question's answer; |
FeedMarkerinterface
A one-line marker: the user's done/reopen, the owner's state or status change.
| Property | Type | Description |
|---|---|---|
type | 'marker' | — |
marker | 'done' | 'reopen' | 'state' | 'status' | — |
from | string | null |
|
to | string | null |
|
MessageBlocktype
One block of a message, by type.
type MessageBlock = MarkdownBlock | FieldsBlock | FormBlock;MarkdownBlockinterface
Markdown text.
| Property | Type |
|---|---|
type | 'markdown' |
text | string |
FieldsBlockinterface
A compact key/value list, shown as aligned label value rows.
| Property | Type |
|---|---|
type | 'fields' |
items | MessageField[] |
MessageFieldinterface
One row of a fields block.
| Property | Type |
|---|---|
label | string |
value | string |
FormBlockinterface
Questions for the user, answered once (inbox.form.submit). A submitted form is frozen: re-sends of its message never change it.
| Property | Type | Description |
|---|---|---|
type | 'form' | — |
id | string | — |
title | string | null | — |
submit | string | The submit button's label. |
questions | FormQuestion[] | — |
state | 'open' | 'submitted' | 'withdrawn' |
|
draft | Record<string, FormAnswer> | Saved partial answers ( |
answers | Record<string, FormAnswer | null> | null | Once submitted, every question's answer ( |
FormQuestiontype
One question of a form, by type.
type FormQuestion = ChoiceQuestion | TextQuestion | ConfirmQuestion;FormAnswertype
An answer: an option id (choice), option ids (multiple choice), text, or a confirm's yes/no.
type FormAnswer = string | string[] | boolean;QuestionBaseinterface
What every question carries.
| Property | Type | Description |
|---|---|---|
id | string | Unique in the form; what answers are keyed by. |
label | string | Inline markdown, one line. |
context | string | null | Markdown shown above the input. |
required | boolean | Must be answered to submit (text: not blank; |
under | string | null | A follow-up of this earlier question, shown under it; |
when | string | null | With |
ChoiceQuestioninterface
Pick one option, or several when multiple.
| Property | Type | Description |
|---|---|---|
type | 'choice' | — |
options | ChoiceOption[] | — |
multiple | boolean | — |
default | string | string[] | null | An option id, or ids when |
ChoiceOptioninterface
One option of a choice question.
| Property | Type |
|---|---|
id | string |
label | string |
description | string | null |
TextQuestioninterface
Free text.
| Property | Type | Description |
|---|---|---|
type | 'text' | — |
placeholder | string | null | — |
default | string | null | Prefilled, editable. |
multiline | boolean | — |
max | number | Longest answer, in bytes. |
ConfirmQuestioninterface
Yes or no.
| Property | Type | Description |
|---|---|---|
type | 'confirm' | — |
yes | string | null | Label of the yes choice; |
no | string | null | Label of the no choice; |
default | boolean | null | — |
FormParamstype
inbox.form.* params: the message holding the form, and answers by question id.
type FormParams = ThreadAddress & { message: string; answers?: Record<string, FormAnswer> };ThreadNoteinterface
One record of a notification thread.
| Property | Type | Description |
|---|---|---|
id | number | — |
level | 'info' | 'warn' | 'error' | — |
msg | string | — |
link | string | null | — |
at | number | Unix seconds. |
ThreadAddresstype
A thread by store id, or an owner thread by owner (instance name or id) and key.
type ThreadAddress = { thread: number } | { owner: string; key: string };NotifyTargettype
One notification thread by store id, or every one.
type NotifyTarget = { thread: number } | { all: true };ForwardRowinterface
One daemon port forward (forwards.list()).
| Property | Type | Description |
|---|---|---|
id | number | Daemon-wide id: what |
dir | string | The canonical config root; with |
local | string | The bound host address, e.g. |
target | string | Route label, e.g. |
process | string | null | The listening process ( |
state | string |
|
conns | number | Open connections. |
configured | boolean | From a sandbox's |
machineoptional | string | The machine whose instance or service it reaches ( |
ForwardAddParamsinterface
forwards.add() params; instance, service, or both.
| Property | Type | Description |
|---|---|---|
dir | string | Config root (the CLI's |
instanceoptional | string | Instance name, as the CLI takes it (never prompts). |
serviceoptional | string | Forward one of its services instead. |
addressoptional | string | Host address to bind. Default |
spec | string |
|
machineoptional | string | A registered machine's instance or service (then |
ForwardAddedinterface
A forward forwards.add() bound.
| Property | Type | Description |
|---|---|---|
id | number | — |
local | string | — |
target | string | Route label, best effort this early. |
InstancesResolvedinterface
instances.resolve's answer: every instance the name could mean, sorted (several: the caller picks).
| Property | Type | Description |
|---|---|---|
matches | string[] | With |
foundoptional | ResolvedInstance[] |
|
ResolvedInstanceinterface
One InstancesResolved match.
| Property | Type | Description |
|---|---|---|
name | string | Its name on its own host (unqualified). |
machine | string | null |
|
root | string | null | Its config root on its host; |
InstanceCancelledinterface
instances.cancel's answer: the in-flight verb's pid was SIGINTed.
| Property | Type |
|---|---|
ok | true |
pid | number |
InstanceRenamedinterface
instances.rename's answer: the new (trimmed) name.
| Property | Type |
|---|---|
instance | string |
InstanceDoneinterface
instances.done's answer: the instance's done flag as it now is.
| Property | Type |
|---|---|
instance | string |
done | boolean |
SandboxEntryinterface
One sandboxes.list entry (not the snapshot's SandboxRow).
| Property | Type | Description |
|---|---|---|
name | string | — |
machineoptional | string | With |
rootoptional | string | The config root defining it: always in |
RootCandidateinterface
One roots.list entry: a config root this host knows of.
| Property | Type | Description |
|---|---|---|
root | string | Absolute, canonicalized (a root that's gone: as recorded). |
sandboxes | SandboxEntry[] | Sorted; |
error | string | null | Why the root's sandboxes can't be read (gone, a config that doesn't load). |
MachineProbeinterface
machines.probe's answer: the machine's devsandbox and its candidate roots.
| Property | Type |
|---|---|
version | string |
protocol | number |
roots | RootCandidate[] |
MachineAddedinterface
machines.add's answer.
| Property | Type | Description |
|---|---|---|
name | string | — |
roots | string[] | As saved: the machine's canonical paths, deduplicated. |
version | string | The machine's devsandbox semver. |
warning | string | null | Set when that semver differs from this daemon's. |
MachineInfointerface
machines.get's answer: what an ssh command to the machine needs.
| Property | Type | Description |
|---|---|---|
name | string | — |
target | string | What ssh takes, or an |
command | string | null | The remote devsandbox as shell text; |
roots | string[] | Config roots on the machine. |
agent | boolean | This host's ssh-agent is relayed to it ( |
MachineHeldinterface
machines.hold's answer.
| Property | Type | Description |
|---|---|---|
ok | true | — |
agent | boolean | The machine's agent relay is up; always |
MachineRowinterface
One registered machine (machines.list).
| Property | Type | Description |
|---|---|---|
name | string | — |
target | string | What ssh takes, or an |
roots | string[] | Config roots on the machine. |
command | string | null | The remote devsandbox as shell text; |
agent | boolean | This host's ssh-agent is relayed to it ( |
state | LinkState | — |
error | string | null | Why it's |
version | string | null | The machine's devsandbox semver, once reached. |
ProcessRowinterface
One process of an instance, as ps printed it.
| Property | Type |
|---|---|
pid | string |
ppid | string |
args | string |
RunRowinterface
One tracked run of an instance's helper (devsbd run ls).
| Property | Type | Description |
|---|---|---|
id | string | — |
state | string |
|
started | string | RFC 3339. |
argv | string | The command, space-joined. |
ProcsListinginterface
A running instance's processes and runs (instances.procs).
| Property | Type | Description |
|---|---|---|
processes | ProcessRow[] | — |
signalable | boolean | The pids are the container's own, so the process can be signalled; false for the runtime's host-side |
runs | RunRow[] | Oldest first; |
ProcsErrorinterface
Why an instance has no listing: no such instance, not running, or the listing failed.
| Property | Type |
|---|---|
error | string |
InstanceProcstype
One instance's instances.procs entry.
type InstanceProcs = ProcsListing | ProcsError;BuildLogTailinterface
instances.buildLog's answer: the end of the instance's build log.
| Property | Type | Description |
|---|---|---|
text | string | — |
cut | boolean | Earlier lines were left out. |
ContainerLogsinterface
containers.logs's answer: the container's last output lines.
| Property | Type |
|---|---|
text | string |
SandboxConfiginterface
sandboxes.get's answer: the sandbox's config as TOML text.
| Property | Type | Description |
|---|---|---|
original | string | The table as written, |
resolved | string | Merged with what it |
hash | string | The merged table's config hash; empty when it doesn't merge. |
ServiceConfiginterface
services.get's answer: the service's table as TOML text (services don't extends).
| Property | Type |
|---|---|
original | string |
ForwardRemovedinterface
What forwards.rm() stopped.
| Property | Type | Description |
|---|---|---|
ok | true | — |
local | string | — |
configured | boolean | A configured forward stays stopped until its owner runs again. |
InboxChangedinterface
inbox.changed params: the store changed, re-fetch.
| Property | Type | Description |
|---|---|---|
generation | number | Grows per change this daemon saw; compare within one connection only. |
InboxShowninterface
inbox.shown params: a container message worth a status line.
| Property | Type | Description |
|---|---|---|
instance | string | — |
line | string | The dashboard's status-line text. |
ForwardsStatusinterface
forwards.status params: a one-line forward status.
| Property | Type |
|---|---|
line | string |
VerbParamsinterface
What every verb (run, rebuild, start, stop, rm, services.rebuild) takes: the config root and the env the verb runs with (the caller's whole env, never the daemon's).
| Property | Type | Description |
|---|---|---|
root | string | Absolute config root (the CLI's |
env | Record<string, string> | — |
machineoptional | string | Run it on that machine (a fresh ssh); answered as it answers there. A hang-up cancels it there unless |
TtySizeinterface
A terminal's size in cells.
| Property | Type |
|---|---|
cols | number |
rows | number |
RunParamsinterface
run params: the CLI's flags.
| Property | Type | Description |
|---|---|---|
sandbox | string | — |
nameoptional | string | null | — |
branchoptional | string | null | — |
baseoptional | string | null | — |
jsonoptional | boolean | The run record arrives on |
detachoptional | boolean | Answer once the instance is registered. |
ttyoptional | TtySize | null | Run the verb's commands on a pty of this size (each side 1 to 1000), so output is coloured and |
RebuildParamsinterface
rebuild params: instance or all: true.
| Property | Type | Description |
|---|---|---|
instanceoptional | string | null | — |
alloptional | boolean | — |
forceoptional | boolean | — |
detachoptional | boolean | — |
ttyoptional | TtySize | null | As |
StartParamsinterface
start params: instance or all: true.
| Property | Type | Description |
|---|---|---|
instanceoptional | string | null | — |
alloptional | boolean | — |
detachoptional | boolean | — |
ttyoptional | TtySize | null | As |
StopParamsinterface
stop params: instance or all: true.
| Property | Type | Description |
|---|---|---|
instanceoptional | string | null | — |
alloptional | boolean | — |
detachoptional | boolean | A hang-up before the answer leaves it running instead of cancelling it; the answer still comes at the exit. |
RmParamsinterface
rm params.
| Property | Type | Description |
|---|---|---|
instance | string | — |
deleteBranchoptional | boolean | null |
|
forceoptional | boolean | — |
askoptional | boolean | Where the branch question would come up, answer |
detachoptional | boolean | A hang-up before the answer leaves it running instead of cancelling it; the answer still comes at the exit. |
ServicesRebuildParamsinterface
services.rebuild params: the service's name in the config root.
| Property | Type | Description |
|---|---|---|
name | string | — |
detachoptional | boolean | A hang-up before the answer leaves it running instead of cancelling it; the answer still comes at the exit. |
VerbResultinterface
A verb's answer once it exited 0.
| Property | Type | Description |
|---|---|---|
instance | string | null | The instance it acted on; |
exit | 0 | — |
VerbDetachedinterface
A detach verb's early answer; the verb runs on.
| Property | Type | Description |
|---|---|---|
instance | string | null | — |
detached | true | — |
recordoptional | RunRecord |
|
VerbFailedDatainterface
data of a failed error: the verb exited non-zero.
| Property | Type |
|---|---|
exit | number |
instance | string | null |
VerbOutputinterface
output params: a chunk of a verb's stdout or stderr.
| Property | Type | Description |
|---|---|---|
request | number | The verb request's id. |
stream | 'stdout' | 'stderr' | — |
data | string | UTF-8 (lossy), as read. |
VerbProgressinterface
progress params: a verb's instance changed phase.
| Property | Type | Description |
|---|---|---|
request | number | — |
instance | string | — |
phase | string |
|
Closinginterface
closing params: the daemon is exiting; connect again (which starts a new one).
| Property | Type |
|---|---|
reason | 'handoff' | 'idle' | 'shutdown' |
ApiNotificationinterface
Any daemon notification, known or not (the notification event).
| Property | Type |
|---|---|
method | string |
params | unknown |
ApiCloseinterface
Why a connection closed (the close event).
| Property | Type | Description |
|---|---|---|
code | number | null | The relay's exit code: 0 after |
signal | NodeJS.Signals | null | — |
ApiEventsinterface
Events an Api emits, by name. Notifications need subscribe() first.
| Property | Type | Description |
|---|---|---|
inbox.changed | InboxChanged | — |
inbox.shown | InboxShown | — |
instances.changed | {} | — |
instances.snapshot | InstancesSnapshot | A root this connection watches ( |
forwards.changed | {} | — |
forwards.status | ForwardsStatus | — |
output | VerbOutput | A verb request's output; sent to its connection, no |
progress | VerbProgress | A verb request's phase change; sent to its connection, no |
closing | Closing | — |
notification | ApiNotification | Every notification, including ones this package doesn't know yet. |
close | ApiClose | The relay exited; pending calls were rejected with code |
ApiMethodsinterface
Params and result of each typed method, for Api's call.
| Property | Type | Description |
|---|---|---|
inbox.threads.list | { params: { view?: InboxView }; result: ThreadSummary[] } | — |
inbox.thread.get | { params: ThreadAddress; result: ThreadDetail } | — |
inbox.thread.markRead | { params: ThreadAddress; result: OkResult } | — |
inbox.thread.act | { params: ThreadAddress & { action: string }; result: OkResult } | — |
inbox.thread.reply | { params: ThreadAddress & { text: string }; result: OkResult } | — |
inbox.thread.done | { params: ThreadAddress; result: OkResult } | — |
inbox.thread.reopen | { params: ThreadAddress; result: OkResult } | — |
inbox.form.saveDraft | { params: FormParams; result: OkResult } | Merge |
inbox.form.submit | { params: FormParams; result: OkResult } | Submit an open form: |
inbox.notify.dismiss | { params: NotifyTarget; result: OkResult } | — |
inbox.notify.markRead | { params: NotifyTarget; result: OkResult } | — |
instances.list | { params: { dir: string; depth?: SnapshotDepth; machine?: string }; result: InstancesList } |
|
instances.watch | { params: { dir: string; machines?: boolean }; result: OkResult } | Push |
instances.unwatch | { params: { dir: string }; result: OkResult } | Stop |
instances.resolve | { params: { name: string; machines?: boolean; machine?: string }; result: InstancesResolved } |
|
instances.cancel | { params: { instance: string; machine?: string }; result: InstanceCancelled } | SIGINT an in-flight |
instances.procs | { params: { instances: string[]; machine?: string }; result: Record<string, InstanceProcs> } | Per named instance (exact names), its processes and runs or an |
instances.buildLog | { params: { instance: string; lines?: number; ansi?: boolean; machine?: string }; result: BuildLogTail | null } |
|
instances.signal | { params: { instance: string; pid: string; signal: 'TERM' | 'KILL'; machine?: string }; result: OkResult } | Signal a process in the instance's container (exact name; |
instances.rename | { params: { instance: string; newName: string; machine?: string }; result: InstanceRenamed } | Exact name; |
instances.done | { params: { instance: string; done: boolean; machine?: string }; result: InstanceDone } | Set or clear the done flag (exact name); idempotent. |
containers.logs | { params: { container: string; lines?: number; machine?: string }; result: ContainerLogs } |
|
containers.inspect | { params: { container: string; machine?: string }; result: unknown } |
|
sandboxes.list | { params: { root: string; machines?: boolean; machine?: string }; result: SandboxEntry[] } | The config root's sandboxes, sorted; |
roots.list | { params: { paths?: string[] }; result: RootCandidate[] } | This host's config roots: every one its instances were made from, plus |
machines.probe | { params: { target: string; command?: string }; result: MachineProbe } | Dial a target over ssh and list its candidate roots; |
machines.add | { params: { target: string; name?: string; roots: string[]; agent?: boolean; command?: string }; result: MachineAdded } | Check |
machines.list | { params: {}; result: MachineRow[] } | — |
machines.set | { params: { name: string; agent: boolean }; result: OkResult } | Change a registered machine's settings; |
machines.rm | { params: { name: string }; result: OkResult } | — |
machines.get | { params: { name: string }; result: MachineInfo } | One registered machine, to build an ssh command to it; |
machines.hold | { params: { name: string; agent?: string }; result: MachineHeld } | Hold a machine's link (and, with |
sandboxes.get | { params: { root: string; name: string; machine?: string }; result: SandboxConfig } |
|
services.get | { params: { root: string; name: string; machine?: string }; result: ServiceConfig } | — |
forwards.list | { params: { dir?: string; machines?: boolean }; result: ForwardRow[] } | — |
forwards.add | { params: ForwardAddParams; result: ForwardAdded } | — |
forwards.rm | { params: { id: number }; result: ForwardRemoved } | — |
run | { params: RunParams; result: VerbResult | VerbDetached } | Verbs hold the connection until they exit (or a |
rebuild | { params: RebuildParams; result: VerbResult | VerbDetached } | — |
start | { params: StartParams; result: VerbResult | VerbDetached } | — |
stop | { params: StopParams; result: VerbResult } | — |
rm | { params: RmParams; result: VerbResult } | — |
services.rebuild | { params: ServicesRebuildParams; result: VerbResult } | No instance verb: |
subscribe | { params: { topics: ApiTopic[] }; result: OkResult } | — |
unsubscribe | { params: { topics: ApiTopic[] }; result: OkResult } | — |
shutdown | { params: {}; result: OkResult } | Stop the daemon (it drains, then exits); |
ApiInboxinterface
inbox.* methods; mutations resolve once the store is written.
| Property | Type | Description |
|---|---|---|
list | (view?: InboxView) => Promise<ThreadSummary[]> | Threads in |
get | (thread: ThreadAddress) => Promise<ThreadDetail> | — |
markRead | (thread: ThreadAddress) => Promise<void> | — |
act | (thread: ThreadAddress, action: string) => Promise<void> | Press an owner's action (its event; host-only actions are refused). |
reply | (thread: ThreadAddress, text: string) => Promise<void> | Send a reply; trimmed, cut at 2000 chars. |
done | (thread: ThreadAddress) => Promise<void> | — |
reopen | (thread: ThreadAddress) => Promise<void> | — |
dismiss | (target: NotifyTarget) => Promise<void> | Remove one notification thread, or every one. |
markNotifyRead | (target: NotifyTarget) => Promise<void> | Mark one notification thread read, or every one. |
ApiInstancesinterface
instances.* methods.
| Property | Type | Description |
|---|---|---|
list | (dir: string) => Promise<InstancesList> | The |
ApiForwardsinterface
forwards.* methods. Ad-hoc forwards outlive the connection until rm.
| Property | Type | Description |
|---|---|---|
list | (dir?: string) => Promise<ForwardRow[]> | Forwards of config root |
add | (params: ForwardAddParams) => Promise<ForwardAdded> | Start an ad-hoc forward; resolves once its listener is bound. |
rm | (id: number) => Promise<ForwardRemoved> | — |
Apiinterface
A connection to the daemon (connect()), an EventEmitter of ApiEvents.
| Property | Type | Description |
|---|---|---|
daemonreadonly | HelloResult | The daemon's |
closedreadonly | boolean | The relay has exited; calls reject with code |
call | <M extends string>( method: M, params?: M extends keyof ApiMethods ? ApiMethods[M]['params'] : unknown, ) => Promise<M extends keyof ApiMethods ? ApiMethods[M]['result'] : unknown> | Any method; typed for |
subscribe | (topics: readonly ApiTopic[]) => Promise<void> | Start notifications for |
unsubscribe | (topics: readonly ApiTopic[]) => Promise<void> | — |
on | <E extends keyof ApiEvents>(event: E, listener: (params: ApiEvents[E]) => void) => Api | — |
once | <E extends keyof ApiEvents>(event: E, listener: (params: ApiEvents[E]) => void) => Api | — |
off | <E extends keyof ApiEvents>(event: E, listener: (params: ApiEvents[E]) => void) => Api | — |
close | () => Promise<void> | Hang up: closes the relay's stdin, resolves once it exited. |
inbox | ApiInbox | — |
instances | ApiInstances | — |
forwards | ApiForwards | — |
ConnectOptionsinterface
| Property | Type | Description |
|---|---|---|
nameoptional | string | Sent as |
envoptional | NodeJS.ProcessEnv | — |
stderroptional | 'pipe' | 'inherit' |
|
Errors
A command that exits non-zero rejects with a DevsandboxError carrying its arguments and captured output. exec() is the exception: it resolves with the command's exit code, and cli() does the same with reject: false.
DevsandboxErrorclass
Rejection for a failed CLI invocation.
| Property | Type |
|---|---|
namereadonly | 'DevsandboxError' |
argsreadonly | string[] |
exitCodereadonly | number | null |
signalreadonly | NodeJS.Signals | null |
stdoutreadonly | string |
stderrreadonly | string |
DevsandboxApiErrorclass
Rejection of an API call. code is the daemon's (not-found, invalid, denied, closed-form, bind-failed, failed, unknown-method, internal, …) or the client's own: closed (the connection ended), protocol, unsupported.
| Property | Type | Description |
|---|---|---|
namereadonly | 'DevsandboxApiError' | — |
codereadonly | string | — |
methodreadonly | string | The method called; |
datareadonlyoptional | unknown | The error body's |
try {
await devsandbox.start('web');
} catch (e) {
if (!(e instanceof devsandbox.DevsandboxError)) throw e;
console.error(e.args, e.exitCode, e.stderr);
}Constants
SCHEMAconst
JSON envelope version this package understands.
const SCHEMA: 1;PROTOCOLconst
The API protocol number this package speaks; connect() rejects any other.
const PROTOCOL: 1;Source: npm/devsandboxes/index.d.tsView source on GitHub(opens in a new tab)