The CleanStart Source Intelligence Core SDK for TypeScript provides programmatic access to vulnerability data, package metadata, and supply chain intelligence. Query CVEs, track fix status, and monitor dependencies in your Node.js and browser-based applications.
Installation
Install the SDK from npm using one of the following commands. You can use npm with npm install @cleanstart/intelligence. Alternatively, you can use yarn with yarn add @cleanstart/intelligence. If you prefer pnpm, use pnpm add @cleanstart/intelligence. After installation, verify it was successful by running npm list @cleanstart/intelligence.
Configuration
Set your API key as an environment variable with export CLEANSTART_API_KEY="your-api-key-here". Alternatively, you can pass it directly when creating the client as shown below.
import { IntelligenceClient } from '@cleanstart/intelligence'; const client = new IntelligenceClient({ apiKey: 'your-api-key-here'});To obtain an API key, visit dashboard.cleanstart.com and follow these steps. First, log in to your account. Next, navigate to Settings > API Keys. Then click Generate New Key. Select the scope Source Intelligence Read (minimum). Finally, copy the key and store it securely.
First Query
Query vulnerabilities by CVE ID using the code below.
import { IntelligenceClient } from '@cleanstart/intelligence'; const client = new IntelligenceClient(); async function main() { try { // Query CVE const vuln = await client.vulnerabilities.getByCveId('CVE-2024-1234'); console.log(`CVE: ${vuln.cveId}`); console.log(`Severity: ${vuln.severity}`); console.log(`CVSS Score: ${vuln.cvssScore}`); console.log(`Description: ${vuln.description}`); } catch (error) { console.error('Error:', error); }} main();Querying Vulnerabilities
By CVE ID
const vuln = await client.vulnerabilities.getByCveId('CVE-2024-1234'); console.log({ cveId: vuln.cveId, severity: vuln.severity, cvssScore: vuln.cvssScore, description: vuln.description, affectedPackages: vuln.affectedPackages, fixAvailable: vuln.fixAvailable,});By Package Name
const vulnerabilities = await client.vulnerabilities.getByPackage({ packageName: 'django', ecosystem: 'pypi', limit: 10,}); for (const vuln of vulnerabilities.results) { console.log(`${vuln.cveId}: ${vuln.description}`);}By Ecosystem
const vulnerabilities = await client.vulnerabilities.getByEcosystem({ ecosystem: 'npm', severity: 'HIGH', limit: 50,}); console.log(`Found ${vulnerabilities.results.length} HIGH severity vulnerabilities`); for (const vuln of vulnerabilities.results) { console.log(`- ${vuln.cveId}: ${vuln.affectedPackages}`);}Advanced Search with Filtering
const vulnerabilities = await client.vulnerabilities.search({ severityMin: 'HIGH', cvssScoreMin: 7.0, hasFix: true, publishedAfter: '2024-01-01', page: 1, limit: 20,}); console.log(`Total results: ${vulnerabilities.pagination.total}`);console.log(`Page: ${vulnerabilities.pagination.page} of ${vulnerabilities.pagination.pages}`); for (const vuln of vulnerabilities.results) { console.log(`- ${vuln.cveId}`);}Paginated Results
// Iterate through all pagesasync function getAllResults() { let page = 1; const allVulns: Vulnerability[] = []; while (true) { const results = await client.vulnerabilities.search({ severityMin: 'HIGH', page, limit: 100, }); allVulns.push(...results.results); if (!results.pagination.hasNext) { break; } page++; } return allVulns;} const allVulnerabilities = await getAllResults();console.log(`Total vulnerabilities: ${allVulnerabilities.length}`);Package and Version Information
Get Package Metadata
const pkg = await client.packages.getMetadata({ name: 'requests', ecosystem: 'pypi',}); console.log({ name: pkg.name, latestVersion: pkg.latestVersion, repositoryUrl: pkg.repositoryUrl, description: pkg.description, license: pkg.license,});Check if Vulnerability is Fixed
const isFixed = await client.packages.isVulnerabilityFixed({ packageName: 'django', ecosystem: 'pypi', version: '4.2.8', cveId: 'CVE-2024-1234',}); if (isFixed) { console.log('Vulnerability is fixed in Django 4.2.8');} else { console.log('Upgrade required');}Get Version History
const versions = await client.packages.getVersions({ packageName: 'requests', ecosystem: 'pypi',}); for (const version of versions.results) { if (version.vulnerabilities.length > 0) { console.log(`${version.version}: ${version.vulnerabilities.length} vulnerabilities`); } else { console.log(`${version.version}: Clean`); }}Find Latest Safe Version
const safeVersion = await client.packages.getLatestSafeVersion({ packageName: 'requests', ecosystem: 'pypi',}); if (safeVersion) { console.log(`Latest safe version: ${safeVersion}`); console.log(`Upgrade available: ${safeVersion > 'X.Y.Z'}`);} else { console.log('No safe version found');}Dependency Graph Traversal
Get Package Dependencies
const dependencies = await client.dependencies.getDependencies({ packageName: 'django', version: '4.2.0', ecosystem: 'pypi',}); for (const dep of dependencies.results) { console.log(`- ${dep.packageName} ${dep.versionSpec}`);}Get Transitive Dependencies
const allDependencies = await client.dependencies.getTransitiveDependencies({ packageName: 'requests', version: '2.31.0', ecosystem: 'pypi',}); for (const dep of allDependencies.results) { const path = dep.path.join(' -> '); console.log(`${path} (version: ${dep.version})`);}Find Vulnerabilities in Dependency Tree
const vulnsInTree = await client.dependencies.findVulnerabilitiesInTree({ packageName: 'django', version: '4.2.0', ecosystem: 'pypi',}); for (const vuln of vulnsInTree.results) { console.log(`Vulnerability: ${vuln.cveId}`); console.log(`Path: ${vuln.path.join(' -> ')}`); console.log(`Severity: ${vuln.severity}\n`);}Exploit Prediction Scoring (EPSS)
Get EPSS Score
const epss = await client.vulnerabilities.getEpss({ cveId: 'CVE-2024-1234',}); console.log(`EPSS Score: ${epss.score.toFixed(2)}`); // 0.0 to 1.0console.log(`Percentile: ${epss.percentile}`); // 0-100console.log(`Severity: ${epss.severity}`); if (epss.score > 0.5) { console.log('High exploit probability - prioritize patching');}Batch EPSS Lookup
const cveIds = [ 'CVE-2024-1234', 'CVE-2024-5678', 'CVE-2024-9999',]; const epssData = await client.vulnerabilities.getEpssBatch({ cveIds,}); for (const [cveId, epss] of Object.entries(epssData)) { console.log(`${cveId}: ${epss.score.toFixed(2)} (percentile: ${epss.percentile})`);}Advisory Subscriptions
Get Security Advisories
const advisories = await client.advisories.getByPackage({ packageName: 'django', ecosystem: 'pypi',}); for (const advisory of advisories.results) { console.log(`Title: ${advisory.title}`); console.log(`Description: ${advisory.description}`); console.log(`Affected versions: ${advisory.affectedVersions}`); console.log(`Fix version: ${advisory.fixedVersion}`); console.log(`Published: ${advisory.publishedDate}\n`);}Register Webhook
const webhook = await client.webhooks.register({ url: 'https://your-app.example.com/webhooks/advisories', events: ['advisory.created', 'advisory.updated'], packages: [ { name: 'django', ecosystem: 'pypi' }, { name: 'requests', ecosystem: 'pypi' }, ],}); console.log(`Webhook ID: ${webhook.id}`);console.log(`Endpoint: ${webhook.url}`);console.log(`Created: ${webhook.createdAt}`);Verify Webhook Signature
import crypto from 'crypto'; function verifyWebhookSignature( secret: string, payload: Buffer, signature: string): boolean { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );} // In your webhook handlerimport express from 'express'; const app = express(); app.post('/webhooks/advisories', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-signature'] as string; if (!verifyWebhookSignature(process.env.WEBHOOK_SECRET!, req.body, signature)) { return res.status(401).json({ error: 'Invalid signature' }); } const advisory = JSON.parse(req.body.toString()); // Process advisory res.json({ status: 'received' });}); app.listen(3000);Response Types
Vulnerability Interface
interface Vulnerability { cveId: string; description: string; severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'NONE'; cvssScore: number; affectedPackages: AffectedPackage[]; fixAvailable: boolean; fixedVersion?: string; disclosureDate: string; publishedDate: string; lastModifiedDate: string;} interface AffectedPackage { name: string; ecosystem: string; versions: string[];}Package Interface
interface Package { name: string; ecosystem: string; latestVersion: string; repositoryUrl: string; description: string; license: string; vulnerabilities: Vulnerability[];}Paginated Response
interface PaginatedResults<T> { results: T[]; pagination: { page: number; limit: number; total: number; pages: number; hasNext: boolean; };}Error Handling
Error Types
import { NotFoundError, RateLimitError, ValidationError, AuthenticationError,} from '@cleanstart/intelligence'; try { const vuln = await client.vulnerabilities.getByCveId('CVE-2024-1234');} catch (error) { if (error instanceof NotFoundError) { console.error('Resource not found:', error.message); } else if (error instanceof RateLimitError) { console.error(`Rate limited. Retry after: ${error.retryAfter} seconds`); } else if (error instanceof ValidationError) { console.error('Invalid input:', error.message); } else if (error instanceof AuthenticationError) { console.error('Authentication failed:', error.message); } else { console.error('Unknown error:', error); }}Retry Logic with Exponential Backoff
async function withRetry<T>( fn: () => Promise<T>, maxRetries: number = 3, initialDelay: number = 1000): Promise<T> { let lastError: Error | undefined; for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (error instanceof RateLimitError) { const delay = initialDelay * Math.pow(2, i); console.log(`Rate limited. Waiting ${delay}ms...`); await new Promise(resolve => setTimeout(resolve, delay)); lastError = error; } else { throw error; } } } throw lastError || new Error('Max retries exceeded');} // Usageconst vuln = await withRetry(() => client.vulnerabilities.getByCveId('CVE-2024-1234'));Bulk Operations
Batch Query Multiple CVEs
const cveIds = [ 'CVE-2024-1234', 'CVE-2024-5678', 'CVE-2024-9999',]; const results = await client.vulnerabilities.getBatch({ cveIds,}); for (const [cveId, vuln] of Object.entries(results)) { if (vuln) { console.log(`${cveId}: ${vuln.severity}`); } else { console.log(`${cveId}: Not found`); }}Scan package.json
import fs from 'fs'; interface PackageJson { dependencies?: Record<string, string>; devDependencies?: Record<string, string>;} async function scanPackageJson(filePath: string) { const packageJson: PackageJson = JSON.parse(fs.readFileSync(filePath, 'utf-8')); const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; const vulnerabilities: Array<{ package: string; version: string; cveId: string; severity: string; }> = []; for (const [packageName, versionRange] of Object.entries(allDeps)) { const vulns = await client.vulnerabilities.getByPackage({ packageName, ecosystem: 'npm', }); for (const vuln of vulns.results) { vulnerabilities.push({ package: packageName, version: versionRange, cveId: vuln.cveId, severity: vuln.severity, }); } } return vulnerabilities;} // Run scanconst results = await scanPackageJson('package.json');console.table(results);Logging and Debugging
Enable Debug Mode
const client = new IntelligenceClient({ debug: true, logger: { debug: (msg) => console.debug('[DEBUG]', msg), info: (msg) => console.info('[INFO]', msg), warn: (msg) => console.warn('[WARN]', msg), error: (msg) => console.error('[ERROR]', msg), },});Custom HTTP Client
import axios from 'axios'; const httpClient = axios.create({ timeout: 30000, maxRedirects: 5, httpAgent: { keepAlive: true, }, httpsAgent: { keepAlive: true, },}); const client = new IntelligenceClient({ httpClient,});Rate Limiting and Quotas
Default rate limits are 1,000 requests per minute, 10,000 requests per hour, and 100,000 requests per day.
Rate limit info is available after each request:
const vuln = await client.vulnerabilities.getByCveId('CVE-2024-1234'); // Check rate limit headersconsole.log(`Remaining this minute: ${vuln.rateLimitRemaining}`);console.log(`Rate limit resets at: ${vuln.rateLimitReset}`);Caching
The SDK includes optional client-side caching:
const client = new IntelligenceClient({ cacheTtl: 3600, // 1 hour in seconds}); // First call hits APIconst vuln1 = await client.vulnerabilities.getByCveId('CVE-2024-1234'); // Second call uses cacheconst vuln2 = await client.vulnerabilities.getByCveId('CVE-2024-1234'); // Clear cacheclient.clearCache(); // Disable cache for specific queryconst vuln3 = await client.vulnerabilities.getByCveId('CVE-2024-1234', { useCache: false,});Examples
Security Audit Report Generator
interface AuditResult { name: string; version: string; vulnerabilityCount: number; criticalCount: number; highCount: number; updateAvailable: boolean; latestVersion: string;} async function generateAuditReport(packageJsonPath: string): Promise<AuditResult[]> { const packageJson: PackageJson = JSON.parse( fs.readFileSync(packageJsonPath, 'utf-8') ); const results: AuditResult[] = []; const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; for (const [packageName] of Object.entries(allDeps)) { const vulns = await client.vulnerabilities.getByPackage({ packageName, ecosystem: 'npm', }); const pkg = await client.packages.getMetadata({ name: packageName, ecosystem: 'npm', }); const criticalCount = vulns.results.filter(v => v.severity === 'CRITICAL').length; const highCount = vulns.results.filter(v => v.severity === 'HIGH').length; results.push({ name: packageName, version: allDeps[packageName], vulnerabilityCount: vulns.results.length, criticalCount, highCount, updateAvailable: allDeps[packageName] !== pkg.latestVersion, latestVersion: pkg.latestVersion, }); } return results;} // Generate and display reportconst report = await generateAuditReport('package.json');console.table(report);Continuous Monitoring with Polling
async function monitorPackage( packageName: string, checkIntervalSeconds: number = 3600) { while (true) { try { const vulns = await client.vulnerabilities.getByPackage({ packageName, ecosystem: 'npm', }); if (vulns.results.length > 0) { console.log(`⚠️ Found ${vulns.results.length} vulnerabilities in ${packageName}`); for (const vuln of vulns.results.slice(0, 5)) { console.log(` - ${vuln.cveId}: ${vuln.severity}`); } } else { console.log(`✅ No vulnerabilities found in ${packageName}`); } } catch (error) { console.error(`Error checking ${packageName}:`, error); } // Wait before next check await new Promise(resolve => setTimeout(resolve, checkIntervalSeconds * 1000)); }} // Monitor packagesmonitorPackage('express');monitorPackage('react');Express Middleware for Dependency Checks
import express, { Request, Response, NextFunction } from 'express'; interface RequestWithDeps extends Request { dependencies?: { vulnerable: string[]; critical: string[]; };} const dependencyCheckMiddleware = ( client: IntelligenceClient) => { return async ( req: RequestWithDeps, _res: Response, next: NextFunction ) => { try { const packageJson: PackageJson = JSON.parse( fs.readFileSync('package.json', 'utf-8') ); const vulnerable: string[] = []; const critical: string[] = []; const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies, }; for (const [packageName] of Object.entries(allDeps)) { const vulns = await client.vulnerabilities.getByPackage({ packageName, ecosystem: 'npm', }); if (vulns.results.length > 0) { vulnerable.push(packageName); if (vulns.results.some(v => v.severity === 'CRITICAL')) { critical.push(packageName); } } } req.dependencies = { vulnerable, critical }; } catch (error) { console.error('Error checking dependencies:', error); } next(); };}; const app = express();app.use(dependencyCheckMiddleware(client)); app.get('/health', (req: RequestWithDeps, res) => { res.json({ status: 'ok', dependencies: req.dependencies, });});Next Steps
API Reference: See Source Intelligence Core API docs for complete endpoint documentation (internal use). Authentication: Learn about API key management. Examples: Explore integration samples for common patterns. GitHub: View source code on GitHub.
