TypeScript SDK
@cheetahengineering/cheetah-client — install from GitHub Packages, connect, typed usage, and error handling.
@cheetahengineering/cheetah-client wraps the open REST API for Node ≥ 18. ESM, Promise-based throughout, fully typed.
Install#
The package is published to the GitHub Packages registry, not public npm. You need a GitHub token with read:packages scope.
In your project's .npmrc:
@cheetahengineering:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
In package.json, pin the version matching your cell's cheetah-service:
"@cheetahengineering/cheetah-client": "0.0.132"
Install with the token in the environment:
GITHUB_TOKEN=$(gh auth token) pnpm install
${GITHUB_TOKEN} must be set at install time — without it the registry returns a 404 for the package, which is GitHub's way of saying "unauthorized."
Connect#
import { CheetahClient } from "@cheetahengineering/cheetah-client";
const client = new CheetahClient("http://cheetah-cell.local:8000");
console.log(await client.health());
The constructor takes the cell's base URL and an optional { timeout } in milliseconds (default 30000 — note the unit differs from the Python SDK's seconds). Every method returns a Promise; there is no close method to call.
The public surface#
How the SDK maps onto the API reference. Method names are camelCase; response fields mirror the wire format and stay snake_case (run.serial_number):
| Method | Endpoint |
|---|---|
client.health() |
GET /health |
client.programs.list() · .get(programId) |
GET /programs · GET /programs/{program_id} |
client.programs.listAllRuns({...}) |
GET /runs — options: programId, status, serialNumber, updatedSince, limit, offset |
client.programs.listRuns(programId, {...}) |
GET /programs/{program_id}/runs |
client.programs.getRun(runId) · .getActiveRun() |
GET /runs/{run_id} · GET /runs/active |
client.programs.getRunQualityReport(runId) |
GET /runs/{run_id}/quality-report |
client.programs.downloadClSweepCsv(runId, stepIndex) |
GET /runs/{run_id}/steps/{step_index}/cl_sweep.csv — returns string |
client.sensor.getFrame(frameId) · .getFrameFiles(frameId) |
GET /sensor/frames/{frame_id} · …/files |
client.sensor.downloadPly(frameId, raw = false) |
GET …/file.ply (raw → …/file.raw.ply) — returns ArrayBuffer |
client.sensor.downloadPng(frameId, luminance = false) |
GET …/file.png (luminance → …/file.luminance.png) — returns ArrayBuffer |
client.sensor.downloadNpy(frameId) |
GET …/file.npy — returns ArrayBuffer |
client.webhooks.list() · .get() · .create({...}) · .update() · .delete() |
/webhooks management |
client.webhooks.test(webhookId) |
POST /webhooks/{webhook_id}/test |
client.webhooks.listDeliveries(webhookId, {...}) · .getDeliveryDetail(deliveryId) · .retryDelivery(deliveryId) |
Delivery log and replay |
The SDK exposes more than this — see scope for what that means.
Putting it together#
Recent inspection results with their QC outcomes:
import { CheetahClient } from "@cheetahengineering/cheetah-client";
const client = new CheetahClient("http://cheetah-cell.local:8000");
const page = await client.programs.listAllRuns({ status: "completed", limit: 10 });
for (const run of page.runs) {
const report = await client.programs.getRunQualityReport(run.id);
if (report.quality_report) {
console.log(run.serial_number, run.revision, report.quality_report.status);
}
}
Every response is typed — page is a ProgramRunSummaryList, and the types are all exported from the package root. For the production polling pattern behind this loop, see incremental sync.
Errors#
All SDK errors derive from CheetahError:
| Class | Thrown when |
|---|---|
ConnectionError |
The cell can't be reached — network problem, not an API one |
APIError |
Any HTTP error; carries statusCode, code, params from the error envelope |
NotFoundError |
404s — a subclass of APIError with resource and resourceId |
import { CheetahClient, NotFoundError } from "@cheetahengineering/cheetah-client";
const client = new CheetahClient("http://cheetah-cell.local:8000");
try {
await client.programs.getRun("0196a3f2-7c1e-7d2a-b3a4-9e8d1c2b3a4f");
} catch (err) {
if (err instanceof NotFoundError) {
console.error(`no such ${err.resource}: ${err.resourceId}`);
} else {
throw err;
}
}
Which failures are worth retrying is covered in Errors and retries.
Next#
- API reference — the schemas behind every typed response.
- Open REST API — polling and sync patterns to build with these methods.
- Python SDK — the same surface for Python.