Skip to content
pols.so docs
Esc
↑↓navigate↵open⌘Jpreview
On this page

TypeScript client

Use pols from Node.js with the typed TypeScript client, generated from the same OpenAPI spec as the API.

@zuschaua/pols-client is a typed client for the pols API. Its types are generated from the API’s OpenAPI spec, so they match the API exactly; on top of them it adds helpers for waiting, streaming and computer use.

Install

The package is published on GitHub Packages. Point the @zuschaua scope at it in your project’s .npmrc, then install it:

@zuschaua:registry=https://npm.pkg.github.com
npm install @zuschaua/pols-client

GitHub Packages asks npm to authenticate even for reading; log in with a GitHub token that may read packages (npm login --scope=@zuschaua --registry=https://npm.pkg.github.com). If npm still cannot find the package, write to team@peweo.com for access.

Create, run, clean up

import { createPolsClient } from "@zuschaua/pols-client";

const pols = createPolsClient({ apiKey: process.env.POLS_API_KEY! });

let sb = await pols.sandboxes.create({
  name: "ci-run",
  size: "large",
  env: { NODE_ENV: "test" },
  secrets: ["GITHUB_TOKEN"], // vault entries, set as environment variables
});
sb = await pols.sandboxes.waitFor(sb); // until it runs

for await (const ev of pols.execStream(sb.id, { command: ["bash", "-lc", "npm test"] })) {
  if (ev.type === "stdout") process.stdout.write(ev.data ?? "");
  if (ev.type === "stderr") process.stderr.write(ev.data ?? "");
  if (ev.type === "exit") console.log("exit code", ev.exit_code);
}

await pols.files.write(sb.id, "/home/user/notes.md", "# notes");
const bytes = await pols.files.read(sb.id, "/home/user/notes.md");

await pols.sandboxes.waitFor(await pols.sandboxes.stop(sb.id));

Lifecycle calls return as soon as the API accepted them; waitFor polls until the sandbox reached its desired state.

What the client covers

Area Calls
Sandboxes pols.sandboxes.list, .get, .create, .fork, .stop, .resume, .delete, .stats, .waitFor
Commands pols.exec (collected output), pols.execStream (streamed events)
Files pols.files.read, pols.files.write
Templates pols.templates.list, .get, .create, .delete
Vault pols.vault.list
Org pols.org, pols.orgStats, pols.usage, pols.apiKeys.list
Computer use pols.computer.screenshot, .click, .doubleClick, .drag, .type, .key, .scroll, .action; pols.browser.cdp
Access pols.ports.list, .publish, .unpublish, .link; pols.desktop.link; pols.sshKeys.list, .create, .delete; pols.ssh

For anything without a helper, pols.raw is the typed openapi-fetch client for every endpoint.

createPolsClient takes the apiKey, and optionally a baseUrl (default https://api.pols.so) and a custom fetch. It refuses a plain http:// base URL other than localhost unless you set allowInsecureHttp. waitFor gives up after 5 minutes unless you pass timeoutMs, and throws when the sandbox ends in error.

Errors

Failed calls throw a PolsError with the HTTP status and the API’s stable error code, such as quota_exceeded or not_found. See Errors for what each code means.

Computer use and the browser

import { chromium } from "playwright";

const png = await pols.computer.screenshot(sb.id); // Uint8Array, a PNG
await pols.computer.click(sb.id, 960, 540);
await pols.computer.type(sb.id, "hello");

const { websocket_url } = await pols.browser.cdp(sb.id); // connect within 5 minutes
const browser = await chromium.connectOverCDP(websocket_url);

See Computer use.