Node 18+ · package @cavsnode/cavs-sdk

The TypeScript SDK

A promise-based, fully typed client for CAVS Hub. Streamed hashing, presigned transfers, dedup-aware uploads and a typed error hierarchy with automatic retries — all behind CAVS.fromEnv().

Install
bash
$ npm install @cavsnode/cavs-sdk

Requires Node 18 or newer. Ships ESM + CJS with bundled type declarations. Defaults X-CAVS-Integration to javascript-sdk and sends its version in User-Agent.

Quickstart
upload an artifact
import { CAVS } from "@cavsnode/cavs-sdk";
const client = CAVS.fromEnv();
const artifact = await client.artifacts.upload({
path: "./model",
project: "vision-models",
name: "resnet50",
kind: "model",
version: "1.4.0",
});
console.log(artifact.reference);
Integration steps

From install to CI.

Five steps take you from an empty environment to an artifact uploaded and restored inside a pipeline.

1 Install the package

Add @cavsnode/cavs-sdk to your project and commit the lockfile for reproducible builds.

$ npm install @cavsnode/cavs-sdk

2 Create a service account & export a token

Create a service account in the CAVS dashboard scoped to artifacts:read and artifacts:write, then export its cavs_sk_ key. Never commit tokens; the SDK redacts them from logs and errors.

$ export CAVS_TOKEN=cavs_sk_...
$ export CAVS_API=https://cavsnode.com   # or your self-hosted Hub

3 Your first upload

upload() streams a sha256 per file, opens a session, skips objects the Hub already stores, PUTs the rest to presigned URLs, then finalizes a version and resolves with dedup stats.

const client = CAVS.fromEnv();
const artifact = await client.artifacts.upload({
  path: "./model", project: "vision-models",
  name: "resnet50", kind: "model", version: "1.4.0",
});
console.log(artifact.reference, artifact.deduplicationRatio);

4 Your first download

download() authorizes object ids, streams each to a temp file while hashing, verifies the sha256 against the oid (throwing ChecksumError on mismatch), then atomically renames into place.

await client.artifacts.download({
  reference: "cavs://acme-ai/vision-models/model/resnet50:1.4.0",
  dest: "./restored",
});

5 Use it in CI

Store the token as a secret and run a small publish script from any job.

# .github/workflows/publish.yml (job step)
- run: npm ci && node publish.mjs
  env:
    CAVS_TOKEN: ${{ secrets.CAVS_TOKEN }}
    CAVS_API: https://cavsnode.com
Errors & retries

Typed failures, safe retries.

Every rejection is a subclass of CAVSError. Transient failures (429, 5xx, transport) retry automatically — up to 4 attempts with exponential backoff and jitter, honouring Retry-After (capped ~30s).

  • AuthenticationError — 401 · AuthorizationError — 403
  • NotFoundError — 404 · ConflictError — 409
  • QuotaExceededError — 413 / 402
  • RateLimitError — 429 (respects Retry-After)
  • ChecksumError — download hash mismatch
  • UploadError / DownloadError — transport
import { CAVS, QuotaExceededError, AuthenticationError }
  from "@cavsnode/cavs-sdk";

const client = CAVS.fromEnv();
try {
  await client.artifacts.upload({ path: "./model",
    project: "p", name: "m", kind: "model", version: "1.0.0" });
} catch (err) {
  if (err instanceof QuotaExceededError) alert("quota hit");
  else if (err instanceof AuthenticationError) alert("bad token");
  else throw err;
}
Redaction is on by default. The token never appears in toString(), thrown errors, or logs — it is shown as cavs_sk_…abcd.