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
}
| Option | Env | Default |
|---|---|---|
apiKey | CYBROS_API_KEY | — |
baseUrl | CYBROS_API_URL | https://backend.cybros.hacktigerlabs.com/api/v1 |
fetch | — | globalThis.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
| Method | Returns |
|---|---|
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}/findingsendpoint.
client.findings
| Method | Returns |
|---|---|
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
| Method | Returns |
|---|---|
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
| Method | Returns |
|---|---|
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
| Method | Returns |
|---|---|
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
| Method | Returns |
|---|---|
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
| Method | Returns |
|---|---|
list(params?: AuditListParams) | Promise<Page<AuditLog>> |
client.repositories
| Method | Returns |
|---|---|
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 keysCLI, the dashboard, or the/api-keysAPI.
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.