npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@microsandbox/agent-client

v0.7.6

Published

Low-level TypeScript access to the microsandbox agent protocol. `AgentClient` is `Client<AgentProtocol>` from `@microsandbox/protocol-client`; the agent package supplies relay setup, its existing encoder, and generation gates. The shared engine owns frami

Readme

@microsandbox/agent-client

Low-level TypeScript access to the microsandbox agent protocol. AgentClient is Client<AgentProtocol> from @microsandbox/protocol-client; the agent package supplies relay setup, its existing encoder, and generation gates. The shared engine owns framing, IDs, queues, cancellation, and transport lifetime. Sandbox lifecycle and process/filesystem convenience APIs belong to the SDK.

AgentProtocol (setup, encoder, gates)
                 |
          Client<AgentProtocol>
            /          \
 native / encoded     raw / exact packets
                 |
       Unix socket / named pipe / WebSocket

Installation and entry points

Install with npm install @microsandbox/agent-client. Node.js 22 or newer is required for native transports. The root entry is browser-safe. @microsandbox/agent-client/node imports Node's net module and accepts native endpoint paths verbatim, including Windows named-pipe names.

Native messages

import { connectUnix } from "@microsandbox/agent-client/node";
import { typedMessage } from "@microsandbox/agent-client";

const client = await connectUnix("/tmp/msb-agent.sock", { setupTimeoutMs: 10_000 });
try {
  const response = await client.request(typedMessage("core.fs.request", {
    op: { Stat: { path: "/etc/os-release", follow_symlink: true } },
  }), { requestTimeoutMs: 5_000 });
  console.log(response.type, response.decodePayload());
  console.log(client.ready.agentVersion, client.ready.negotiatedVersion);
} finally {
  await client.close();
}

typedMessage(name, value) asks the agent codec to encode a native payload. encodedMessage(name, bytes) supplies only the application payload; it does not supply an envelope or framed packet. Both paths apply known message gates and flags. Names are open strings, so extensions remain accessible without editing an enum. These methods do not validate an application schema. requestTyped() accepts an optional checked request with its own result decoder and requires a terminal response.

The current TypeScript agent encoder continues to emit generation-five envelopes, including its existing CBOR map and byte-string representations. The ready generation controls feature gates. The supported pre-0.5 relay prologue selects generation-one envelopes and rejects unavailable filesystem/TCP operations before sending. The captured ready frame and unknown fields remain available through client.ready.frame and client.ready.readyBytes.

Browser streams

import { AgentClient, WebSocketConnector, typedMessage } from "@microsandbox/agent-client";

const client = await AgentClient.connectConnector(
  new WebSocketConnector("wss://relay.example.com/agent"),
  { setupTimeoutMs: 10_000 },
);
try {
  const stream = await client.openStream(typedMessage("core.exec.request", {
    cmd: "sh", args: ["-lc", "echo hello"],
  }));
  try {
    for await (const frame of stream) {
      console.log(frame.type, frame.payload);
    }
  } finally {
    stream.close();
  }
} finally {
  await client.close();
}

The relay must forward the agent's binary byte stream, including its prologue. WebSocketTransport also wraps a caller-constructed socket for custom authentication. Its incoming queue defaults to 8 MiB and 4096 messages; overflow closes the connection because browser WebSockets cannot pause incoming messages. Outgoing writes wait for the browser's send queue to drain. The connector and handshake share one setup deadline.

Raw and exact access

import { type AgentClient, TransportPacket } from "@microsandbox/agent-client";

async function exchangeOpaque(client: AgentClient, envelope: Uint8Array) {
  const stream = await client.openStreamRaw(0, envelope);
  const { sender, receiver } = stream.split();
  try {
    await sender.send(0, envelope);
    await client.sendRaw(sender.id, 0, envelope);
    return await receiver.next({ requestTimeoutMs: 5_000 });
  } finally {
    receiver.close();
    sender.close();
  }
}

async function forwardExactPacket(client: AgentClient, bytes: Uint8Array) {
  await client.writeUnchecked(TransportPacket.fromBytes(bytes));
}

Raw APIs leave envelope and payload bytes opaque. requestRaw(flags, body) returns the first raw reply. openStreamRaw() receives through the terminal reply. sendRaw(id, flags, body) requires an active ID owned by this connection. A split sender retains its original lease and cannot regain permission if the numeric ID is reused. writeUnchecked(bytes) can write even deliberately malformed transport bytes; TransportPacket.fromBytes() optionally validates a single packet first.

Native replies retain the complete original raw frame as frame.raw, including unknown envelope fields. core.error is an ordinary terminal agent response; interpreting it belongs to the caller or a checked request decoder.

Ownership and failures

Streams own their send and receive halves. split() transfers those halves and invalidates the original stream's send/receive methods. Closing a receiver or leaving async iteration stops local delivery; it sends no remote cancel, signal, or EOF. An abandoned ID remains draining until its terminal frame arrives. A timed-out next() does not consume the next arriving frame.

client.clone() shares the connection. client.close() closes every shared handle and wakes pending operations. Explicitly close clients and streams: JavaScript garbage collection only offers best-effort cleanup. A request deadline covers writer admission and the local response wait; it does not cancel remote execution. ClientError.delivery is not_sent before admission and unknown afterward. Nothing automatically retries an admitted operation.

Migration from the previous package API

| Previous surface | Shared-engine surface | | --- | --- | | Independent AgentClient class/router | AgentClient = Client<AgentProtocol> plus convenience constructors | | handshakeTimeoutMs | setupTimeoutMs, covering dial and handshake together | | client.negotiatedVersion() | client.ready.negotiatedVersion | | Closed MessageType parameter | Open string names; MessageType still lists known names | | Packet-oriented custom AgentTransport | Ordered read(maxBytes), write(bytes), close() byte transport | | InboundFrame.fromRawFrame(frame) | new AgentEnvelopeCodec().decode(frame) | | new AgentStream(...) | Obtain owned streams from client.openStream() or openStreamRaw() | | Request, encoded payload, stream, exact packet methods | Retained on the generic client, with additional raw and split interfaces |

These are public source API changes. Existing agent wire behavior is preserved; source and byte tests do not replace the required historical runtime/SDK launch tests.

Development

From the repository's packages directory, run npm ci, npm run build, npm run typecheck, and npm test. The private workspace links the shared package locally; published dependency metadata uses the release version. The README's TypeScript examples are checked with the public package declarations.