---
title: Session
description: "One running MicroVM's control API, with the proxy auth handled for you."
---

One running MicroVM's control API, with the proxy auth handled for you.

## Methods

### agentToken()

```ts
agentToken(): Promise<string>;
```

The guest bearer credential. Store only in a private encrypted control record.

#### Returns

`Promise`\<`string`>

***

### connectHeaders()

```ts
connectHeaders(port: number): Promise<Record<string, string>>;
```

Both proxy headers for `port`, so a caller can open its **own** connection.

The `{ url, headers }` shape a provider's `getPortEndpoint` answers with: pair these
with `endpoint()` and nothing outside this addon has to know how a proxy token is
minted or when it refreshes. Minted through the session's existing cache, so calling
this does not burn a second control-plane call and does not open a second TRAP-9
schedule.

A plain `Record<string, string>` rather than a class, and that is the one place this
crate's own "never `#[napi(object)]` for anything carrying a closure" rule does not
apply: there is no closure here to protect. The value is a **bearer credential**, and
unlike the token itself it necessarily comes out as a string — a header a caller has to
put on a request cannot be opaque. What is still closed is the other direction: no
function in this addon *takes* a header map, so a caller cannot feed a forged or expired
one back in.

**Empty for a direct session**, which is the true answer rather than a missing one: a
daemon reached directly takes no proxy headers, so an empty object is exactly what its
requests carry.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `port` | `number` |

#### Returns

`Promise`\<`Record`\<`string`, `string`>>

***

### connectSubprotocols()

```ts
connectSubprotocols(port: number): Promise<string[] | null>;
```

The three WebSocket subprotocols for `port`, in the order a handshake offers them.

`new WebSocket(url, await session.connectSubprotocols(port))` is the whole use. A
MicroVM endpoint takes the auth and the target port as `Sec-WebSocket-Protocol` values
rather than as headers, because the browser `WebSocket` constructor cannot set a header
— and the platform strips all three before forwarding, so a server inside the VM never
negotiates them and must not be written to expect them.

`null` for a direct session, and deliberately not an empty array: the subprotocol form
exists only for a request through the endpoint proxy, so there is nothing for a
directly-reached daemon to offer. Answering `["lambda-microvms"]` with no token would
open a handshake refused for a reason naming neither the token nor the port.

The middle string **contains the credential**. Same rule as `connectHeaders`.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `port` | `number` |

#### Returns

`Promise`\<`string`\[] | `null`>

***

### discovery()

```ts
discovery(): Promise<Discovery | null>;
```

Image configuration, or null if this daemon predates discovery.

#### Returns

`Promise`\<[`Discovery`](/microvms-agentd/reference/typescript/interfaces/discovery/) | `null`>

***

### downloadDir()

```ts
downloadDir(
   remote: string, 
   localDir: string, 
   globs: string[]
): Promise<DownloadedFile[]>;
```

Brings the files of a directory in the VM back under `localDir`: the regular files
`globs` select, and nothing else.

The daemon packs `remote`, and the archive describes the VM's filesystem, where
untrusted work runs, so core writes only regular-file members that match a glob, never
under `.git` whatever the globs say, and never outside `localDir`. A symlink, a special
file or a `../` member is skipped, not refused. `['**']` brings every regular file back.
Resolves to what was written; a local directory that can't be written to rejects with
`ERR_INVALID_ARG`.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `remote` | `string` |
| `localDir` | `string` |
| `globs` | `string`\[] |

#### Returns

`Promise`\<[`DownloadedFile`](/microvms-agentd/reference/typescript/interfaces/downloadedfile/)\[]>

***

### downloadFile()

```ts
downloadFile(path: string, options?: DownloadFileOptions | null): Promise<Buffer<ArrayBufferLike>>;
```

Reads one file, or lines `startLine` through `endLine` of it.

The range is 1-based and inclusive, and the daemon slices the file, so reading lines 40
to 60 of a large log reads those lines alone. Either bound may be left out (line 1,
through EOF), and an `endLine` past the last line reads through EOF. Line 0 and an end
before the start reject with `ERR_INVALID_ARG` before any request.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `path` | `string` |
| `options?` | [`DownloadFileOptions`](/microvms-agentd/reference/typescript/interfaces/downloadfileoptions/) | `null` |

#### Returns

`Promise`\<`Buffer`\<`ArrayBufferLike`>>

***

### downloadTar()

```ts
downloadTar(remote: string): Promise<Buffer<ArrayBufferLike>>;
```

The raw tar bytes of a remote tree.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `remote` | `string` |

#### Returns

`Promise`\<`Buffer`\<`ArrayBufferLike`>>

***

### egressPosture()

```ts
egressPosture(): Promise<string>;
```

The launch's egress posture: `"open"`, `"unsealed"`, `"best-effort"`, or `"sealed"`.

The value the CLI envelope's `egressPosture` reports for the same launch options, and
what `egressPostureFor` answers before the launch. A session that does not hold its
launch options (`Session.direct`, `Session.attach`, an adopted sandbox) reports
`"unsealed"`. Advertise network isolation only for `"sealed"`. Async like `endpoint()`,
because a sandbox-held session is read under the sandbox's lock.

#### Returns

`Promise`\<`string`>

***

### endpoint()

```ts
endpoint(): Promise<string>;
```

The endpoint this session addresses.

#### Returns

`Promise`\<`string`>

***

### exec()

```ts
exec(execId: string): Promise<ExecHandle>;
```

A handle for an exec started earlier, possibly by another process.

The reattach path. Nothing is checked against the daemon here — the handle is an id
plus a transport, and a poll is what discovers whether the exec exists.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `execId` | `string` |

#### Returns

`Promise`\<[`ExecHandle`](/microvms-agentd/reference/typescript/classes/exechandle/)>

***

### fileExists()

```ts
fileExists(path: string): Promise<boolean>;
```

Whether a path exists, distinguishing absence from every other refusal.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `path` | `string` |

#### Returns

`Promise`\<`boolean`>

***

### health()

```ts
health(): Promise<Health>;
```

Unauthenticated liveness.

#### Returns

`Promise`\<[`Health`](/microvms-agentd/reference/typescript/interfaces/health/)>

***

### keepAwake()

```ts
keepAwake(options?: KeepAwakeOptions | null): Promise<KeepAwake>;
```

Keeps the VM awake by polling health from this process until stopped.

The platform counts only inbound requests as activity, so an exec working with no
client traffic is suspended once `maxIdleDurationSeconds` passes. Resolves at once
with a running handle. On a sandbox-held session a suspend or terminate through the
sandbox ends the keepalive before its next poll; stop it before suspending through
anything else, or the next poll auto-resumes the VM.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `options?` | [`KeepAwakeOptions`](/microvms-agentd/reference/typescript/interfaces/keepawakeoptions/) | `null` |

#### Returns

`Promise`\<[`KeepAwake`](/microvms-agentd/reference/typescript/classes/keepawake/)>

***

### kill()

```ts
kill(execId: string): Promise<boolean>;
```

Signals an exec's whole process group. Returns whether anything was signalled.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `execId` | `string` |

#### Returns

`Promise`\<`boolean`>

***

### launchMetrics()

```ts
launchMetrics(): Promise<LaunchMetrics | null>;
```

Launch observations, absent for sessions not created by a launch.

#### Returns

`Promise`\<[`LaunchMetrics`](/microvms-agentd/reference/typescript/interfaces/launchmetrics/) | `null`>

***

### port()

```ts
port(): Promise<number>;
```

The port the proxy token is scoped to.

#### Returns

`Promise`\<`number`>

***

### portForward()

```ts
portForward(guestPort: number, options?: ServeOptions | null): Promise<PortForward>;
```

Serves a local port as an HTTP and WebSocket forward to `guestPort` in the VM, on a
background task, and resolves at once with its handle: `microvm port-forward`'s loop.

Connections are served at once rather than one after another, so a slow request
doesn't hold the next. A request the endpoint proxy refuses is listed in the report
with its status while the forward keeps serving.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `guestPort` | `number` |
| `options?` | [`ServeOptions`](/microvms-agentd/reference/typescript/interfaces/serveoptions/) | `null` |

#### Returns

`Promise`\<[`PortForward`](/microvms-agentd/reference/typescript/classes/portforward/)>

***

### procs()

```ts
procs(): Promise<ProcGroup[]>;
```

Process accounting: every registered exec with its group's live pids.

The daemon reads `/proc` itself, so this needs no `ps` in the guest. A `ProcGroup` with
`childExited` and a non-empty `pids` is a command that finished while something it
backgrounded did not; pass its `execId` to `kill`.

#### Returns

`Promise`\<[`ProcGroup`](/microvms-agentd/reference/typescript/interfaces/procgroup/)\[]>

***

### proxyMintCount()

```ts
proxyMintCount(): Promise<number | null>;
```

How many proxy tokens this session has minted, or `null` for a direct session.

Exposed because it is the only observable that distinguishes a client which re-minted
after a resume from one that kept a stale token (STATE-8). The **token itself** is not
exposed and cannot be: the core's `ProxyToken` has no `Display`, no `as_str`, and no
`Deref`, so "treat `authToken` as a string" is as inexpressible here as it is there
(TRAP-7).

#### Returns

`Promise`\<`number` | `null`>

***

### run()

```ts
run(command: string | string[], options?: ExecOptions | null): Promise<ExecHandle>;
```

Starts a command and returns its handle. Does not wait.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `command` | `string` | `string`\[] |
| `options?` | [`ExecOptions`](/microvms-agentd/reference/typescript/interfaces/execoptions/) | `null` |

#### Returns

`Promise`\<[`ExecHandle`](/microvms-agentd/reference/typescript/classes/exechandle/)>

***

### runSync()

```ts
runSync(command: string | string[], options?: ExecOptions | null): Promise<ExecResult>;
```

Start, wait, ack. The one-shot shape, for when output is all you want.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `command` | `string` | `string`\[] |
| `options?` | [`ExecOptions`](/microvms-agentd/reference/typescript/interfaces/execoptions/) | `null` |

#### Returns

`Promise`\<[`ExecResult`](/microvms-agentd/reference/typescript/interfaces/execresult/)>

***

### runToCompletion()

```ts
runToCompletion(
   command: string | string[], 
   options?: CompletionRequest | null, 
   onOutput?: 
  | ((chunk: StreamEvent) => unknown)
  | null
): Promise<ExecResult>;
```

Start, stream, and collect one command: exactly one `ExecResult` back (BIND-6..10).

With `onOutput`, each output chunk (a `StreamEvent` of kind `"output"`) is handed to it
as it arrives. The result then comes from the ack that follows the terminal `exit`
event, or, when the stream ends without one, from a wait and ack. When `timeoutSec +
clientGraceSec` passes first (or, with no `timeoutSec`, the VM's maximum lifetime), the
process group is killed and the exec waited for and acked within `clientGraceSec` once
more; if that fails too the result is synthesized with `posixExitCode` 124.

A throwing `onOutput` stops delivery; the exec is still waited for and acked so nothing
is left behind, and then the promise rejects with the callback's message. `shell: true`
runs `/bin/sh -c`; for bash semantics pass `shell: "bash"` with a script string, or
`["bash", "-c", script]` for a daemon that predates named shells.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `command` | `string` | `string`\[] |
| `options?` | [`CompletionRequest`](/microvms-agentd/reference/typescript/interfaces/completionrequest/) | `null` |
| `onOutput?` | | ((`chunk`: [`StreamEvent`](/microvms-agentd/reference/typescript/interfaces/streamevent/)) => `unknown`) | `null` |

#### Returns

`Promise`\<[`ExecResult`](/microvms-agentd/reference/typescript/interfaces/execresult/)>

***

### spawn()

```ts
spawn(command: string | string[], options?: SpawnOptions | null): Promise<ExecProcess>;
```

Starts a command and returns it as two byte streams, a `wait()`, and a `kill()`.

The **process** shape, as against \[`Self::run`]'s handle shape. Same start request and
the same `ExecOptions` (`cwd`, `env`, `user`, `group`, `shell`, `execId`, `timeoutSec`
all apply), so this is a different view of one exec rather than a different exec:
`spawn` and `run` with the same `execId` address the same server-side child, and the
daemon starts one.

`stdout` and `stderr` come out as independent `ReadableStream<Uint8Array>`, which is
deliberately the AI SDK harness's `SandboxProcess` shape — see \[`crate::process`] for
what that compatibility is and is not, for how one interleaved SSE channel becomes two
streams, and for why an evicted byte range errors the streams by default instead of
being reported out-of-band.

The reconnect-at-cursor behaviour is unchanged from `stream()`: a stream cut by a
suspend/resume rejoins at the byte offset rather than ending, so a suspend does not look
like a clean exit.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `command` | `string` | `string`\[] |
| `options?` | [`SpawnOptions`](/microvms-agentd/reference/typescript/interfaces/spawnoptions/) | `null` |

#### Returns

`Promise`\<[`ExecProcess`](/microvms-agentd/reference/typescript/classes/execprocess/)>

***

### syncDir()

```ts
syncDir(localDir: string, options?: SyncDirOptions | null): Promise<SyncReport>;
```

Syncs `localDir` into the VM's `/workspace` once, uploading only what changed.

Core's one pass, `microvm sync`'s: the local tree is hashed and diffed against the
manifest the last sync left in the VM, the changed members travel as one archive, the
paths gone locally are removed in the VM with one `rm` whose deadline is
`deleteTimeout` seconds (core's default when omitted), and the manifest is rewritten.
`full: true` ignores the manifest and uploads everything. `.git`, `target`,
`node_modules` and `.venv` never travel. A tree over the daemon's budgets rejects with
`ERR_INVALID_ARG` before anything is sent.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `localDir` | `string` |
| `options?` | [`SyncDirOptions`](/microvms-agentd/reference/typescript/interfaces/syncdiroptions/) | `null` |

#### Returns

`Promise`\<[`SyncReport`](/microvms-agentd/reference/typescript/interfaces/syncreport/)>

***

### tunnel()

```ts
tunnel(
   guestPort: number, 
   options?: ServeOptions | null, 
   verifyIdentity?: TunnelIdentity | null
): Promise<Tunnel>;
```

Serves a local TCP port as a tunnel to `guestPort` in the VM, on a background task, and
resolves at once with its handle: `microvm tunnel`'s loop.

Each local connection gets a WebSocket of its own through the endpoint proxy, and a
connection the daemon refuses is listed in the report while the tunnel keeps serving.
With `verifyIdentity` (a `TunnelIdentity`, such as `sandbox.tunnelIdentity()`), each
connection first proves the far end is the daemon of the VM that identity was launched
with, and a connection that can't is refused. A separate parameter rather than an
option, for the reason `buildImage`'s guarded values are: a class in an options object
can't cross an async call.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `guestPort` | `number` |
| `options?` | [`ServeOptions`](/microvms-agentd/reference/typescript/interfaces/serveoptions/) | `null` |
| `verifyIdentity?` | [`TunnelIdentity`](/microvms-agentd/reference/typescript/classes/tunnelidentity/) | `null` |

#### Returns

`Promise`\<[`Tunnel`](/microvms-agentd/reference/typescript/classes/tunnel/)>

***

### uploadFile()

```ts
uploadFile(
   path: string, 
   data: Uint8Array, 
   mode?: string | null
): Promise<void>;
```

Writes one file, creating parents. `mode` is an **octal string** (`"0755"`), which is
the daemon's shape — a number here would be ambiguous between 0o755 and 755.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `path` | `string` |
| `data` | `Uint8Array` |
| `mode?` | `string` | `null` |

#### Returns

`Promise`\<`void`>

***

### uploadTar()

```ts
uploadTar(remote: string, archive: Uint8Array): Promise<void>;
```

Extracts pre-built tar bytes under `remote`.

Bytes rather than a local path: packing a directory is the caller's, because the
symlink and permission decisions in a pack belong to whoever knows what the tree
means.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `remote` | `string` |
| `archive` | `Uint8Array` |

#### Returns

`Promise`\<`void`>

***

### waitUntilReady()

```ts
waitUntilReady(timeout?: number | null): Promise<Health>;
```

Polls health until the daemon reports bootstrapped.

Connection errors on the way are expected rather than exceptional: a VM that has just
reached RUNNING commonly refuses a connection or two before the proxy path is wired
up. A *fatal* error ends the wait at once, because retrying a 401 until the deadline
is the mistake the retryable split exists to prevent.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `timeout?` | `number` | `null` |

#### Returns

`Promise`\<[`Health`](/microvms-agentd/reference/typescript/interfaces/health/)>

***

### attach()

```ts
static attach(
   region: Region, 
   microvmId: string, 
   endpoint: string, 
   agentToken: string, 
   port?: number | null, 
   requestTimeout?: number | null
): Promise<Session>;
```

Reattach using a private control record, without bootstrapping again.
Owns its transport independently of sandbox locks; use a separate attach with
a short requestTimeout for keepalives. Never publish or log agentToken.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `region` | [`Region`](/microvms-agentd/reference/typescript/classes/region/) |
| `microvmId` | `string` |
| `endpoint` | `string` |
| `agentToken` | `string` |
| `port?` | `number` | `null` |
| `requestTimeout?` | `number` | `null` |

#### Returns

`Promise`\<`Session`>

***

### direct()

```ts
static direct(endpoint: string, agentToken: string): Session;
```

A session against a daemon reached **directly**, with no proxy headers.

The shape for a local binary, a test server, or a VM reached over a tunnel. There is
deliberately no constructor that takes a proxy token: minting one is the control
plane's job and it happens inside every request (TRAP-9), so a caller handing a token
in would be handing in one that expires.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `endpoint` | `string` |
| `agentToken` | `string` |

#### Returns

`Session`

## Provenance

This page is generated from `bindings/microvms-js/index.d.ts` by TypeDoc 0.28.20 and typedoc-plugin-markdown 4.13.1, run from `site/scripts/gen-reference.mjs` on every `pnpm run sync`, so an edit made here is overwritten by the next run.

To change the page, change the doc comment in the binding's Rust source, then regenerate the declarations with `mise run dts`. `mise run dts:check` fails when the committed file no longer matches the source.