TypeScript SDK

@cybros/sdk — the official TypeScript client for the Cybros API. Works anywhere a global fetch is available: Node 18+, browsers, VS Code extensions, and edge runtimes. Fully typed responses; forward-compatible with new server fields.


Install

npm install @cybros/sdk
# or
pnpm add @cybros/sdk

Client

import { Cybros } from "@cybros/sdk";

const client = new Cybros({ apiKey: "cybros_sk_..." });

const me = await client.me();
console.log(me.email, me.role);

Constructor

new Cybros(opts?: CybrosOptions)

interface CybrosOptions {
  apiKey?: string;                     // falls back to CYBROS_API_KEY
  baseUrl?: string;                    // falls back to CYBROS_API_URL, then prod
  fetch?: typeof fetch;                // custom fetch impl (default: globalThis.fetch)
  headers?: Record<string, string>;    // extra headers on every request
}
OptionEnvDefault
apiKeyCYBROS_API_KEY
baseUrlCYBROS_API_URLhttps://backend.cybros.hacktigerlabs.com/api/v1
fetchglobalThis.fetch

If no global fetch exists (e.g. Node < 18), pass one explicitly via new Cybros({ fetch }).

Authentication

Auth is Authorization: Bearer <key>, where the key is a cybros_sk_... API key (or a Supabase JWT). Provide it directly or via CYBROS_API_KEY. See Authentication.

Top-level

client.me(): Promise<Me>

const me = await client.me();
console.log(me.active_org_id, me.permissions);

Resources

client.scans

MethodReturns
create(params: ScanCreateParams)Promise<ScanAccepted>
list(params?: ScanListParams)Promise<Page<Scan>>
get(scanId)Promise<Scan>
report(scanId)Promise<ScanReport>
findings(scanId, params?: ScanFindingsParams)Promise<Page<Finding>>
cancel(scanId)Promise<Scan>
wait(scanId, opts?: WaitOptions)Promise<Scan>
// create() returns { scan, estimate } — destructure the scan:
const { scan } = await client.scans.create({
  repository_id: "repo_123",
  ref: "main",
  modules: ["sast", "secrets"],
});

const done = await client.scans.wait(scan.id, {
  onProgress: (s) => console.log("status:", s.status),
});

const findings = await client.scans.findings(done.id, { severity: "high" });
for (const f of findings.items) {
  console.log(`${f.severity}\t${f.file_path}:${f.line}\t${f.title}`);
}

Scan findings come from /findings?scan_id= — there is no /scans/{id}/findings endpoint.

client.findings

MethodReturns
list(params?: FindingListParams)Promise<Page<Finding>>
get(findingId)Promise<FindingDetail>
const detail = await client.findings.get("fnd_1a2b...");
console.log(detail.owasp, detail.cwe, detail.fix?.unified_diff);

client.ai

MethodReturns
analyze(scanId)Promise<AIAnalysis>
get(scanId)Promise<AIAnalysis>
patches(scanId)Promise<Record<string, unknown>>
wait(scanId, opts?)Promise<AIAnalysis>
await client.ai.analyze(scanId);
const analysis = await client.ai.wait(scanId, {
  onProgress: (a) => console.log(a.status),
});
console.log("risk:", analysis.risk_score);

client.remediation

MethodReturns
create(findingId)Promise<RemediationJob>
get(jobId)Promise<RemediationJob>
wait(jobId, opts?: RemediationWaitOptions)Promise<RemediationJob>
const job = await client.remediation.create("fnd_1a2b...");
const done = await client.remediation.wait(job.id);
console.log(done.pr_url, done.branch);

client.compliance

MethodReturns
overview(params?: ComplianceScopeParams)Promise<ComplianceOverview>
framework(frameworkId, params?: ComplianceScopeParams)Promise<FrameworkDetail>
const overview = await client.compliance.overview();
const soc2 = await client.compliance.framework("soc2");

client.aiSecurity

MethodReturns
overview(params?: { scan_id?; repository_id? })Promise<AiSecurityOverview>
const posture = await client.aiSecurity.overview();
console.log(posture.summary.checks_failed, "/", posture.summary.checks_total);

client.audit

MethodReturns
list(params?: AuditListParams)Promise<Page<AuditLog>>

client.repositories

MethodReturns
list(params?: RepositoryListParams)Promise<Page<Repository>>
get(repositoryId)Promise<Repository>
const repos = await client.repositories.list({ limit: 100 });
const match = repos.items.find((r) => r.full_name === "acme/api");

API-key management (create/list/revoke) is not exposed in the TS SDK — use the cybros keys CLI, the dashboard, or the /api-keys API.


Waiting on jobs

scans.wait, ai.wait, and remediation.wait share a WaitOptions shape:

interface WaitOptions {
  onProgress?: (state) => void;   // called on each poll
  intervalMs?: number;            // scans 2000, ai/remediation 3000
  timeoutMs?: number;             // default 600000 (10 min)
  signal?: AbortSignal;           // scans.wait only
}
const controller = new AbortController();
const done = await client.scans.wait(scan.id, {
  intervalMs: 2500,
  onProgress: (s) => console.log(s.status),
  signal: controller.signal,
});

Helper predicates are exported: isTerminalScan, isTerminalAnalysis, isTerminalJob.

Pagination

List methods return Page<T> with items, total, limit, offset:

let offset = 0;
for (;;) {
  const page = await client.scans.list({ limit: 100, offset });
  page.items.forEach((s) => { /* ... */ });
  offset += page.limit;
  if (offset >= page.total) break;
}

Error handling

All failures throw a subclass of CybrosError:

import { CybrosError, AuthError, NotFoundError, RateLimitError } from "@cybros/sdk";

try {
  await client.scans.get("nope");
} catch (err) {
  if (err instanceof NotFoundError) { /* 404 */ }
  else if (err instanceof AuthError) { /* 401 / 403 */ }
  else if (err instanceof RateLimitError) { console.log(err.retryAfter); /* 429 */ }
  else if (err instanceof CybrosError) { console.log(err.status, err.body); }
}

CybrosError exposes .status, .body, and .requestId.

Environments

Node (18+)

import { Cybros } from "@cybros/sdk";
const client = new Cybros(); // reads CYBROS_API_KEY from process.env

Browser / VS Code extension

Pass the key from your own secret store (never hard-code it in client-side code):

// e.g. from VS Code SecretStorage
const key = await context.secrets.get("cybros.apiKey");
const client = new Cybros({ apiKey: key });
const me = await client.me();

The env fallbacks are guarded for runtimes without process, so the client is safe to bundle for the browser.

Types

Package exports include Cybros, CybrosOptions, DEFAULT_BASE_URL, the error classes, all response types (Me, Repository, Scan, ScanAccepted, ScanReport, Finding, FindingDetail, AIAnalysis, RemediationJob, ComplianceOverview, FrameworkDetail, AiSecurityOverview, AuditLog, Page<T>, Severity), and the param/predicate helpers. All interfaces are forward-compatible — unknown server fields are preserved.

See also