TypeScript SDK

TypeScript SDK

The official @tektona/sdk client for Node.js, Bun, Deno, and edge runtimes.

@tektona/sdk is the official TypeScript client for the Tektona API. It runs on Node.js (≥ 22), Bun, Deno, and edge runtimes that expose fetch.

The SDK is alpha, and APIs may change before 1.0. It exposes one service per API resource off a single client: sandbox, secret, project, org, registry, repository, gitCredential, egressNetworkPolicy, egressProxyProfile, and location. Each resource has its own reference page in the sidebar.

Install

pnpm add @tektona/sdk

Configuration

The client reads credentials and default scope from environment variables:

TEKTONA_API_KEY=...
TEKTONA_API_URL=https://api-dev.tektona.ai   # optional override
TEKTONA_ORG=my-org                # optional default org
TEKTONA_PROJECT=my-project        # optional default project

Or pass them explicitly:

import { Tektona } from '@tektona/sdk';

const tek = new Tektona({
  apiKey: process.env.TEKTONA_API_KEY,
  apiUrl: 'https://api-dev.tektona.ai',             // optional
  timeoutMs: 60_000,                 // optional, default 60s
  headers: { 'X-My-Header': 'foo' }, // optional
  org: 'my-org',                     // optional default scope
  project: 'my-project',
});

Scope: org and project

Most resources live under an org and project. Rather than repeating them on every call, set a default org/project on the client; any call can still override per-invocation:

const tek = new Tektona({ apiKey, org: 'acme', project: 'web' });

await tek.secret.list();                  // uses acme/web
await tek.secret.list({ project: 'api' }); // override just this call
await tek.org.list();                      // top-level, ignores scope

A scoped call with no org/project available (neither per-call nor default) throws InvalidArgumentError naming exactly what is missing.

Quick start

import { Tektona } from '@tektona/sdk';

const tek = new Tektona({ org: 'my-org', project: 'my-project' });

const sandbox = await tek.sandbox.create({
  image: 'ghcr.io/tektona-ai/desktop-x11:0.4.3',
  egressNetworkPolicy: 'tektona/open',
});

console.log(sandbox.id, sandbox.state);

tek.sandbox.create returns a Sandbox instance bound to the client. See the Sandbox reference for the full lifecycle surface.

Pagination

Every list() returns a single Page<T> and accepts an optional cursor / limit:

const page = await tek.sandbox.list({ limit: 50 });
console.log(page.items, page.hasMore, page.nextCursor, page.totalCount);

// next page
if (page.hasMore) {
  await tek.sandbox.list({ cursor: page.nextCursor });
}

For convenience, list-backed services also expose an auto-paging async iterator that walks every page for you:

for await (const sandbox of tek.sandbox.listAll()) {
  console.log(sandbox.id);
}

Errors

Errors are typed and instanceof-friendly. They form a hierarchy rooted at TektonaError; HTTP responses map to ApiError subclasses carrying the statusCode:

import {
  TektonaError,        // root
  ApiError,            // any HTTP-status error (has .statusCode)
  AuthenticationError, // 401
  AuthorizationError,  // 403
  InvalidArgumentError,// 400 / 422
  NotFoundError,       // 404 (→ SandboxNotFoundError, SecretNotFoundError, …)
  ConflictError,       // 409
  QuotaExceededError,  // 402
  RateLimitError,      // 429 (has .retryAfterMs, .throttler, .limit, .remaining, .resetSeconds)
  isHttpStatus,
} from '@tektona/sdk';

try {
  await tek.sandbox.create({ image: '…' });
} catch (err) {
  if (isHttpStatus(err, 404)) {
    // not found
  } else if (err instanceof RateLimitError) {
    // back off using err.retryAfterMs; err.throttler tells you which limit was
    // hit ("general" or "sandbox-create"), and err.remaining / err.resetSeconds
    // mirror the X-RateLimit-* response headers.
  }
  throw err;
}

isHttpStatus(err, status) is the canonical way to branch on HTTP status across every TektonaError subclass.

Tree-shaking

The ergonomic services are the recommended surface. For minimal bundles (browser or edge), the generated, fully tree-shakeable transport functions are re-exported under generated:

import { generated } from '@tektona/sdk';
// import { listSandboxes } from '@tektona/sdk/generated' — call a single operation

On this page