Skip to content
Raster
Esc
navigateopen⌘Jpreview
On this page

Streams

Live frames and pty bytes over the websocket gateway.

Frames and pty bytes do not go through the API — they go through a gateway the API mints a short-lived ticket for. Both SDKs do the ticket, the socket and the frame decoding for you.

In Python this needs the realtime extra:

pip install "raster[realtime]"

Screen

const stream = await machine.screen.stream();

for await (const frame of stream) {
  frame.seq; // monotonic
  frame.width;
  frame.height;
  frame.image; // Uint8Array — a JPEG
}

stream.close();
with machine.screen.stream() as stream:
    for frame in stream:
        frame.seq      # monotonic
        frame.width
        frame.height
        frame.image    # bytes — a JPEG

A screen stream opens a session but never takes the input lease, so watching a desktop cannot evict whoever is driving it.

A frame is decoded from the gateway’s 20-byte binary header rather than from JSON, so its fields are read as properties in both languages — this is the one place the Python SDK hands back a dataclass instead of a TypedDict.

Terminals

const term = await machine.terminal.connect(); // opens a pty if you pass no id

term.write("ls -la\n");
term.resize(120, 32);

for await (const bytes of term) process.stdout.write(bytes);

term.close(); // closes the pty inside the machine
with machine.terminal.connect() as term:   # opens a pty if you pass no id
    term.write("ls -la\n")
    term.resize(120, 32)

    for chunk in term:
        print(chunk.decode(errors="replace"), end="")

Bytes go both ways unmodified. Pass an existing terminal id to attach to one you already opened with terminal.open; with no id, one is opened first, which is what makes the common case a single call.

A terminal that already has a client refuses a second at the handshake. In TypeScript, connect also takes the open options (cols, rows, command, cwd, user) for the pty it creates; in Python it takes cols and rows.

term.exitCode (TypeScript) and term.exit_code (Python) are the shell’s exit code once it has exited, and null while it is running.

Lifetime and failure

Closing the connection closes the pty inside the machine. Closing a screen stream just stops the frames.

A refused handshake surfaces as a RasterError carrying the gateway’s close code translated into the product’s vocabulary — unauthenticated for an expired ticket, conflict for a terminal that already has a client, compute_unavailable when the control plane could not be reached. That last one is worth retrying; the others are not. See close codes.

There is no automatic reconnect. A closed socket stays closed, and a caller that wants to resume mints a fresh ticket by calling stream() or connect() again.

Options

TypeScript accepts an AbortSignal and a webSocket implementation for environments without a global one:

const controller = new AbortController();
const stream = await machine.screen.stream({ signal: controller.signal });

For what travels on the wire — channels, the frame header, backpressure and the fence — see the realtime gateway.

Was this page helpful?