Skip to main content

TypeScript SDK

TypeScript client SDK for Boxer — a sandboxed container execution service backed by gVisor. Zero dependencies, works in Node.js, Bun, Deno, and browsers.

Installation

npm install boxer-sdk
# or
pnpm add boxer-sdk

Requires Node.js 18+ (or any runtime with native fetch) and a running Boxer server.

Quick Start

import { BoxerClient } from "boxer-sdk";

const client = new BoxerClient({ baseUrl: "http://localhost:8080" });

const result = await client.run(
"python:3.12-slim",
["python3", "-c", "print('hello world')"],
);
console.log(result.stdout); // hello world
console.log(result.stderr); // (empty)
console.log(result.exit_code); // 0
console.log(result.wall_ms); // e.g. 312

Multi-language Examples

// Python
const result = await client.run(
"python:3.12-slim",
["python3", "-c", "print('hello world')"],
);

// Node.js
const result = await client.run(
"node:20-slim",
["node", "-e", "console.log('hello world')"],
);

// Perl
const result = await client.run(
"perl:5.38-slim",
["perl", "-e", "print 'hello world\n'"],
);

Working with Files

Upload a Script and Run It

Upload a file to the Boxer file store, then reference it by path in run. The file is bind-mounted read-only at /<remotePath> inside the container.

import { readFile } from "node:fs/promises";

const script = await readFile("script.py");
await client.uploadFile("script.py", script);

const result = await client.run(
"python:3.12-slim",
["python3", "/script.py"],
{ files: ["script.py"] },
);

Upload a Local Directory

uploadPath (from boxer-sdk/node) recursively uploads a local file or directory, preserving the directory structure. Returns the list of remote paths, which can be passed directly to files.

import { uploadPath } from "boxer-sdk/node";

// Upload a single file
const filePaths = await uploadPath(client, "./script.py");
// => ["script.py"]

// Upload an entire directory
const dirPaths = await uploadPath(client, "./myproject", "myproject");
// => ["myproject/main.py", "myproject/utils.py", ...]

const result = await client.run(
"python:3.12-slim",
["python3", "/myproject/main.py"],
{ files: dirPaths },
);

Download Output Files

Any file the container writes to /output/ is captured at the end of the run. Set persist: true to retain them for post-run download — without it, output files are deleted once the response is returned.

const code = `
import os, json
os.makedirs('/output', exist_ok=True)
with open('/output/result.json', 'w') as f:
json.dump({'message': 'hello world', 'value': 42}, f)
`;

const script = new TextEncoder().encode(code);
await client.uploadFile("compute.py", script);

const result = await client.run(
"python:3.12-slim",
["python3", "/compute.py"],
{ files: ["compute.py"], persist: true },
);

const data = await client.downloadFile(`output/${result.exec_id}/result.json`);
console.log(new TextDecoder().decode(data));
// {"message": "hello world", "value": 42}

The output path pattern is output/<exec_id>/<relative_path>, preserving any subdirectory structure written under /output/.

Resource Limits

import type { ResourceLimits } from "boxer-sdk";

const limits: ResourceLimits = {
cpu_cores: 0.5,
memory_mb: 128,
wall_clock_secs: 10,
};

const result = await client.run(
"python:3.12-slim",
["python3", "-c", "print('done')"],
{ limits },
);

Error Handling

import { BoxerAPIError, BoxerTimeoutError, BoxerOutputLimitError } from "boxer-sdk";

try {
const result = await client.run(
"python:3.12-slim",
["python3", "-c", "while True: pass"],
{ limits: { wall_clock_secs: 5 } },
);
} catch (err) {
if (err instanceof BoxerTimeoutError) {
console.error("execution timed out");
} else if (err instanceof BoxerOutputLimitError) {
console.error("output exceeded size limit");
} else if (err instanceof BoxerAPIError) {
console.error(`API error ${err.statusCode}: ${err.message}`);
}
}

Runtime Compatibility

The core boxer-sdk package uses only web-standard APIs (fetch, FormData, Blob) with zero dependencies:

RuntimeCore packageboxer-sdk/node
Node.js 18+
Bun
Deno
Browsers

boxer-sdk/node (uploadPath) requires a Node.js-compatible fs module.

Running Tests

Tests require a live Boxer server:

pnpm install
BOXER_URL=http://localhost:8080 pnpm test

Without BOXER_URL all tests are skipped automatically.