SDK Reference / v1.1.4

Build secure AI apps faster with Terso.

Terso SDK security platform

A production-oriented TypeScript client for submitting and monitoring security scans through the Terso API, with privacy-preserving finding proofs anchored on Solana.

Security-first

Keys and private findings stay protected.

Typed API

ESM, CommonJS, and first-class TypeScript.

Proof-ready

Anchor deterministic hashes on Solana.

Get started

Installation

Install the package from npm. Terso requires Node.js 18 or newer, or a modern runtime with standards-compatible fetch, AbortController, and Web APIs.

shell
npm i @labsbtd/terso

Both ESM and CommonJS entry points are included. TypeScript is recommended but optional for consumers.

Keep credentials server-side. Never expose a Terso API key in browser bundles, source control, logs, URLs, or client storage. Use a trusted server or server-side proxy.
Get started

Quick start

Create a client, submit a repository for scanning, and wait for the scan to reach a terminal state.

ts
import { Terso } from "@labsbtd/terso";

const terso = new Terso({
  apiKey: process.env.TERSO_API_KEY!,
  baseUrl: process.env.TERSO_BASE_URL,
});

const scan = await terso.scans.create({
  projectName: "my-app",
  source: {
    type: "repository",
    url: "https://github.com/example/my-app",
    branch: "main",
  },
});

const result = await terso.scans.waitForResult(scan.id);

Provide credentials through your application environment. The SDK deliberately does not load dotenv.

dotenv
TERSO_API_KEY=terso_your_api_key_here
TERSO_BASE_URL=https://api.terso.example/v1
Get started

Configuration

new Terso(options) accepts authentication, transport, retry, and Solana proof settings.

OptionType / DefaultDescription
apiKeystring · requiredBearer credential. Never included in SDK-generated errors.
baseUrlstring · API defaultAPI base URL. Trailing slashes are removed.
timeoutMsnumber · 30000Timeout for each individual HTTP attempt.
maxRetriesnumber · 2Additional attempts for retryable failures.
fetchglobal fetchInject a compatible fetch implementation.
userAgentSuffixstring · noneAppend an application identifier to the user agent.
solanaSolanaProofOptions · devnetCluster, RPC endpoint, and commitment for proofs.
Core SDK

Security scans

Create scans from a repository, remotely hosted archive, or inline code. Optional metadata lets you associate the scan with an environment or workflow.

ts
await terso.scans.create({
  projectName: "service-api",
  source: { type: "archive", url: "https://downloads.example/service.tgz" },
  metadata: { environment: "staging" },
});

await terso.scans.create({
  projectName: "snippet",
  source: { type: "code", content: "const value = input;", filename: "index.ts" },
});

Retrieve and manage scans

ts
const scan = await terso.scans.get("scan_123");
const page = await terso.scans.list({ page: 1, pageSize: 25 });
const cursorPage = await terso.scans.list({ cursor: "next_cursor" });
const cancelled = await terso.scans.cancel("scan_123");

Polling and cancellation

Wait for completed, failed, or cancelled. Polling cleans up its timers when complete, timed out, or aborted.

ts
const controller = new AbortController();
setTimeout(() => controller.abort(), 10_000);

await terso.scans.waitForResult("scan_123", {
  pollingIntervalMs: 2_000,
  timeoutMs: 5 * 60_000,
  signal: controller.signal,
});
Core SDK

Privacy-preserving Solana proofs

Terso hashes a finding locally and records only its deterministic SHA-256 hash through Solana's Memo program. Finding titles, descriptions, files, remediation, and report details never enter the transaction.

ts
import { Keypair } from "@solana/web3.js";
import { Terso, type Finding } from "@labsbtd/terso";

const terso = new Terso({
  apiKey: process.env.TERSO_API_KEY!,
  solana: { cluster: "devnet" },
});

const finding: Finding = {
  id: "finding_123",
  title: "SQL injection",
  description: "Private evidence retained by the report owner",
  severity: "high",
};

const proof = await terso.proofs.create({
  finding,
  signer: Keypair.generate(),
});

const result = await terso.proofs.verify({
  finding,
  transactionSignature: proof.transactionSignature,
});
Solana transactions are public and permanent. The hash, signer address, transaction signature, slot, and terso:v1: marker are public—but the sensitive finding content stays off-chain.

Deterministic verification

proofs.hash(finding) produces the same lowercase digest without a network request. Keys are recursively sorted and undefined properties are omitted. Changing any included value changes the hash.

proofs.verify(input) fetches the transaction, locates the Terso Memo, recomputes the hash locally, checks transaction success, and reports whether the values match. Verification proves content integrity—not whether the finding itself is objectively correct.

SettingSupported valuesDefault
clusterdevnet · testnet · mainnet-beta · customdevnet
rpcUrlValid Solana RPC URLRequired for custom
commitmentprocessed · confirmed · finalizedconfirmed
Core SDK

Errors

Every SDK error extends TersoError, so applications can handle authentication, rate limits, API responses, network failures, validation, and timeouts precisely.

ts
try {
  await terso.scans.get("scan_123");
} catch (error) {
  if (error instanceof TersoRateLimitError) {
    console.error(error.requestId, error.retryAfterMs);
  } else if (error instanceof TersoAuthenticationError) {
    console.error("Check server-side Terso credentials");
  } else if (error instanceof TersoApiError) {
    console.error(error.statusCode, error.code, error.requestId);
  } else if (error instanceof TersoTimeoutError) {
    console.error("The operation timed out");
  }
}
ErrorMeaning
TersoApiErrorAPI error with statusCode, code, requestId, and optional details.
TersoAuthenticationErrorHTTP 401 or 403 authentication failure.
TersoRateLimitErrorHTTP 429 with optional retryAfterMs.
TersoTimeoutErrorA request or polling deadline was exceeded.
TersoNetworkErrorA transport or connectivity failure.
TersoValidationErrorInvalid client input before the request.
Core SDK

Retry and timeout behavior

The client retries network errors and HTTP 408, 429, 500, 502, 503, and 504 responses up to maxRetries. Backoff is capped, exponential, jittered, and honors numeric or HTTP-date Retry-After values.

Authentication and ordinary validation or API failures are not retried. timeoutMs applies to each HTTP attempt; waitForResult has its own total timeout.
Reference

API and types

ExportDescription
TersoMain client exposing scans, health, and proofs APIs.
TersoOptionsClient constructor configuration.
CreateScanInputProject, source, and optional scan metadata.
ScanSourceRepository, archive, or inline code source.
Scan / ScanStatusScan state, lifecycle status, and completed result.
Finding / FindingSeverityFinding data and critical, high, medium, low, or info severity.
PaginationInputPage-based or cursor-based list options.
WaitForResultOptionsPolling interval, timeout, and abort signal.
SolanaProofOptionsCluster, RPC endpoint, and commitment settings.
SolanaProofOn-chain proof transaction receipt.
ProofVerificationVerification result and matched proof details.
VERSIONCurrent SDK version: 1.1.4.

Public methods include scans.create, scans.get, scans.list, scans.cancel, scans.waitForResult, health.check, proofs.hash, proofs.create, and proofs.verify.

Reference

Assumed REST contract

The transport centralizes the documented API assumptions, allowing the base URL to change without changing resource code.

MethodEndpointDescription
POST/scansCreate a scan and return Scan.
GET/scans/{scanId}Retrieve a scan by encoded ID.
GET/scans?page=&pageSize=&cursor=List scans with pagination.
POST/scans/{scanId}/cancelCancel a scan and return its updated state.
GET/healthReturn service status and optional version.

Requests use bearer authentication, JSON content negotiation, X-Terso-SDK-Version, and a user agent. Structured errors are expected as error: { code?, message, details? } with an optional request ID.

Reference

Development and publishing

Run the full local verification pipeline before publishing. prepublishOnly performs package validation, but publishing happens only when explicitly requested.

shell
npm install
npm run typecheck
npm test
npm run test:coverage
npm run lint
npm run format:check
npm run build
npm run validate:package
npm pack
NextTerso platform