TypeScript SDK
A typed, zero-runtime-dependency fetch client. Scaffold status: the
core works (typed client, streaming exec, a frame codec verified against
the conformance fixtures), and it is not yet published to npm. Until
then, consume it from the repo (sdks/ts, source-first: Node ≥ 22.18
runs it directly) or vendor the src/ files.
Server-side runtimes only (Node, Bun, Deno): a daemon token grants control of the host's microVMs and must never ship to a browser.
import { Crucible, NotFoundError } from "@crucible/sdk";
const cr = new Crucible({
baseUrl: "http://127.0.0.1:7878",
token: process.env.CRUCIBLE_TOKEN,
});
// Boot from an OCI image, run a command, stream its output:
const sb = await cr.createSandbox({ image: { oci: "python:3.12-alpine" } });
try {
const res = await cr.exec(sb.id!, { cmd: ["python3", "-c", "print(6*7)"] }, {
onStdout: (chunk) => process.stdout.write(chunk),
onStderr: (chunk) => process.stderr.write(chunk),
});
console.log("exit", res.exit_code, "peak mem", res.usage?.peak_memory_bytes);
// Snapshot the warm state, fork copies (~100ms each):
const snap = await cr.snapshot(sb.id!);
const forks = await cr.fork(snap.id!, 8);
await Promise.all(forks.map((f) =>
cr.exec(f.id!, { cmd: ["python3", "attempt.py"] }).finally(() => cr.deleteSandbox(f.id!)),
));
} finally {
await cr.deleteSandbox(sb.id!);
}What's covered
Sandboxes (create/list/get/delete), streaming exec with stdout/stderr
callbacks, snapshots + fork, images (pull/import/list/delete), durable
logs, file push (putFiles, tar stream) and readFile, the supervised
service API, typed errors (NotFoundError / UnauthorizedError /
PolicyDeniedError over CrucibleError), and Page<T> list shapes,
mirroring the Go SDK surface.
Types are generated from the OpenAPI spec (schema.gen.ts, with
readable aliases in types.ts), so they cannot drift from the daemon.
The frame codec (frames.ts) passes the full
conformance suite against the recorded fixtures; npm test needs no daemon and no KVM.
Not yet built (contributions welcome)
- Interactive exec: the daemon's WebSocket transport
(
GET /sandboxes/{id}/exec+ upgrade) exists and is smoke-tested; the codec here already encodes stdin frames. Contract in the wire doc, reference client in Go atscripts/wsexec. - Log following: poll
logs()with thenext_offsetcursor. - Tar helper: build a
putFilesstream from a local directory. - npm packaging: build output, package name, publish provenance.
See sdks/ts/README.md
for the layout and how each file stays correct.