TypeScript SDK
The TypeScript client provides typed clients for APIGuard, NIS2 Compass, and CITADEL, plus a webhook router with HMAC-SHA256 signature verification. It requires Node.js 18+ or a modern browser, and has zero external runtime dependencies. See SDK & Contracts for the full integration contract reference.
Installation
Install the package from npm:
npm install @opensecstack/sdk
Client construction
Each platform client takes a configuration object with baseURL and apiKey. Optional parameters control request timeouts, retry count, and exponential back-off base. All client methods return Promises and are designed to be used with async/await.
import { APIGuardClient, NIS2CompassClient, CITADELClient } from "@opensecstack/sdk"; class=class="str">"cm">// APIGuard const apiguard = new APIGuardClient({ baseURL: "https:class=class="str">"cm">//apiguard.internal", apiKey: "ag_key_...", timeout: 30_000, class=class="str">"cm">// ms, optional — default 30 s maxRetries: 3, class=class="str">"cm">// optional retryWaitBase: 500, class=class="str">"cm">// ms, optional }); class=class="str">"cm">// NIS2 Compass const nis2 = new NIS2CompassClient({ baseURL: "https:class=class="str">"cm">//nis2compass.internal", apiKey: "nis2_key_...", }); class=class="str">"cm">// CITADEL(HMAC-SHA256 signed) const citadel = new CITADELClient({ baseURL: "https:class=class="str">"cm">//citadel.internal", keyID: "key-001", sharedSecret: "hmac-secret-...", });
Running a scan
Start an APIGuard scan, wait for it to complete, then retrieve and triage findings. Use createScanFull to specify custom modules, target URL, or authentication.
class=class="str">"cm">// Simple scan from spec URL const scan = await apiguard.createScan("https:class=class="str">"cm">//example.com/openapi.json"); console.log(class="str">`Scan ID: ${scan.id}, status: ${scan.status}`); class=class="str">"cm">// Full options — modules, target, bearer auth const scan2 = await apiguard.createScanFull({ spec_url: "https:class=class="str">"cm">//example.com/openapi.json", target: "https:class=class="str">"cm">//api.example.com", modules: ["auth", "injection"], auth_type: "bearer", auth_token: "tok_...", }); class=class="str">"cm">// Poll until complete const completed = await apiguard.getScan(scan.id); class=class="str">"cm">// Retrieve critical findings(paginated) const findings = await apiguard.getFindings(scan.id, { severity: "critical", page: 1, per_page: 50, }); class=class="str">"cm">// Triage a finding await apiguard.patchFinding(findings[0].id, { status: "false_positive", note: "Not applicable in our deployment", }); class=class="str">"cm">// Download a SARIF report const report = await apiguard.getReport(scan.id, "sarif");
NIS2 Compass client
Create an organisation and assessment, update a NIS2 Article 21 control, and upload evidence artifacts. Controls are addressed by their measure_ref (letters a through j per Article 21(2)).
class=class="str">"cm">// Create organisation const org = await nis2.createOrganisation({ name: "Acme Corp", industry: "energy", country: "DE", }); class=class="str">"cm">// Create assessment const assessment = await nis2.createAssessment(org.id, { title: "Q1 2026 NIS2 Assessment", framework_version: "2.0", }); class=class="str">"cm">// List controls that have not been started yet const controls = await nis2.listControls(assessment.id, { status: "not_started", }); class=class="str">"cm">// Mark control class=class="str">"str">'a' as implemented with notes await nis2.patchControl(assessment.id, controls[0].measure_ref, { status: "implemented", notes: "Deployed firewall rules per NIS2 Article 21(2)(a)", risk_score: 2.5, }); class=class="str">"cm">// Upload evidence artifact const artifact = await nis2.uploadArtifact( assessment.id, file, "evidence", { control_id: controls[0].measure_ref, description: "Firewall config evidence", filename: "evidence.pdf" }, ); class=class="str">"cm">// Generate PDF compliance report const pdf = await nis2.generateReport(assessment.id);
CITADEL client
Send security events to the WORM audit chain and verify chain integrity locally. The CITADEL client also exposes AUGUR advisories for threat intelligence lookups.
class=class="str">"cm">// Send an event(fire-and-forget) citadel.sendEvent({ event_type: "apiguard.scan.completed", source: "apiguard", actor_id: "system", actor_type: "system", resource_type: "scan", resource_id: scan.id, severity: "info", payload: { findings_count: 5 }, }); class=class="str">"cm">// Query events from the WORM chain const events = await citadel.getEvents({ source: "apiguard", since: "2026-03-01T00:00:00Z", limit: 100, }); class=class="str">"cm">// Verify TripleHash chain integrity(throws if chain is broken) citadel.verifyChain(events); class=class="str">"cm">// Fetch active AUGUR advisories const active = await citadel.getActiveAdvisories();
Webhook router
The WebhookRouter verifies incoming HMAC-SHA256 signatures, enforces the ±5-minute replay window, and dispatches typed events to registered handlers. It integrates with any Node.js HTTP server.
import { WebhookRouter, EventAPIScanCompleted } from "@opensecstack/sdk"; import http from "node:http"; const router = new WebhookRouter("my-shared-secret"); router .on(EventAPIScanCompleted, (event) => { console.log("Scan completed:", event.id, event.payload); }) .on("*", (event) => { console.log("Unhandled event:", event.event_type); }); class=class="str">"cm">// Mount on a plain Node.js HTTP server http.createServer((req, res) => router.handleHttp(req, res)).listen(3000);
For standalone signature verification (useful in Express / Koa middleware):
import { verifySignature, InvalidSignatureError } from "@opensecstack/sdk"; try { verifySignature(rawBody, req.headers["x-citadel-signature"] as string, secret); } catch(err) { if (err instanceof InvalidSignatureError) { res.status(400).send("Bad signature"); } }
Error handling
All client methods throw instances of OpenSecStackError or its subclasses. Catch RateLimitError to implement back-off; its retryAfter property gives the wait time in seconds.
import { OpenSecStackError, RateLimitError } from "@opensecstack/sdk"; try { await apiguard.getScan("nonexistent-id"); } catch(err) { if (err instanceof RateLimitError) { console.log(class="str">`Rate limited — retry after ${err.retryAfter}s`); } else if (err instanceof OpenSecStackError) { console.log(class="str">`API error ${err.statusCode}: ${err.message}`); if (err.code) console.log(class="str">`Error code: ${err.code}`); } }
Full documentation
Other SDK language clients: Go SDK, Python SDK, Rust SDK.
The complete TypeScript client reference — including all method signatures, option types, and configuration defaults — is available in the SDK repository: