Command Palette
Search for a command to run...
TypeScript
TypeScript SDK with full type safety and modern async patterns
Installation & Setup
Required dependencies and project setup for TypeScript
Package Installation
npm install axios
npm install --save-dev @types/node typescript
npx tsc --initNote: This example uses Axios for HTTP requests. You can replace it with fetch, node-fetch, or any other HTTP client.
Quick Start Example
Simple example to get you started with TypeScript
Basic Usage
import { LeakZeroClient } from './leakzero-client';
const client = new LeakZeroClient(process.env.LEAKZERO_API_KEY!);
async function basicSearch() {
const results = await client.regularSearch({
field: 'email',
value: '[email protected]',
rowLimit: 100
});
console.log(`Found ${results.totalResults} records`);
console.log(`Cost: $${results.cost.toFixed(6)}`);
}Production ReadyComplete TypeScript Implementation
Full-featured client with type safety, error handling, and retry logic
leakzero-client.ts
import axios, { AxiosInstance, AxiosError } from 'axios';
interface SearchOptions {
field: string;
value: string;
option?: 'exact' | 'wildcard' | 'regex';
rowLimit?: number;
autoExport?: {
format: 'json' | 'csv' | 'txt';
enableAutoExport: boolean;
};
}
interface SearchResult {
data: BreachRecord[];
totalResults: number;
cost: number;
requestId: string;
processingTime: number;
}
interface BreachRecord {
email?: string;
password?: string;
username?: string;
phone?: string;
name?: string;
breach_name: string;
breach_date: string;
[key: string]: any;
}
interface BalanceResponse {
balance: number;
currency: string;
}
interface UsageStats {
totalRequests: number;
totalRowsReturned: number;
totalCost: number;
averageResponseTime: number;
}
interface ApiError {
error: string;
message: string;
statusCode: number;
retryAfter?: number;
}
class LeakZeroClient {
private apiKey: string;
private baseURL: string;
private client: AxiosInstance;
private maxRetries: number;
private defaultTimeout: number;
constructor(
apiKey: string,
options: {
baseURL?: string;
maxRetries?: number;
timeout?: number;
} = {}
) {
this.apiKey = apiKey;
this.baseURL = options.baseURL || 'https://api.leakzero.io/api/v1';
this.maxRetries = options.maxRetries || 3;
this.defaultTimeout = options.timeout || 120000;
this.client = axios.create({
baseURL: this.baseURL,
timeout: this.defaultTimeout,
headers: {
'Content-Type': 'application/json',
'User-Agent': 'LeakZero-TypeScript-SDK/1.0.0',
},
});
this.setupInterceptors();
}
private setupInterceptors(): void {
this.client.interceptors.request.use(
(config) => {
const timestamp = new Date().toISOString();
config.headers['x-api-key'] = this.apiKey;
config.headers['x-timestamp'] = timestamp;
config.headers['x-request-id'] = this.generateRequestId();
return config;
},
(error) => Promise.reject(error)
);
this.client.interceptors.response.use(
(response) => {
console.log(`API Request successful: ${response.config.method?.toUpperCase()} ${response.config.url}`);
return response;
},
async (error: AxiosError) => {
const config = error.config as any;
if (!config || config.__retryCount >= this.maxRetries) {
return Promise.reject(this.formatError(error));
}
config.__retryCount = config.__retryCount || 0;
config.__retryCount++;
if (error.response?.status === 429) {
const retryAfter = parseInt(error.response.headers['retry-after'] || '5');
const delay = Math.min(retryAfter * 1000, 30000);
console.warn(`Rate limited. Retrying after ${delay}ms (attempt ${config.__retryCount}/${this.maxRetries})`);
await this.delay(delay);
return this.client(config);
}
if (error.response?.status && error.response.status >= 500) {
const delay = Math.min(1000 * Math.pow(2, config.__retryCount - 1), 10000);
console.warn(`Server error. Retrying after ${delay}ms (attempt ${config.__retryCount}/${this.maxRetries})`);
await this.delay(delay);
return this.client(config);
}
return Promise.reject(this.formatError(error));
}
);
}
private generateRequestId(): string {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
private formatError(error: AxiosError): ApiError {
const response = error.response;
const data = response?.data as any;
return {
error: data?.error || 'API_ERROR',
message: data?.message || error.message || 'An unknown error occurred',
statusCode: response?.status || 0,
retryAfter: response?.headers['retry-after']
? parseInt(response.headers['retry-after'])
: undefined,
};
}
async getBalance(): Promise<BalanceResponse> {
try {
const response = await this.client.get('/public/balance');
return response.data;
} catch (error) {
console.error('Failed to get balance:', error);
throw error;
}
}
async regularSearch(options: SearchOptions): Promise<SearchResult> {
try {
const payload = {
field: options.field,
value: options.value,
option: options.option || 'exact',
rowLimit: Math.min(options.rowLimit || 1000, 10000),
...(options.autoExport && { autoExport: JSON.stringify(options.autoExport) })
};
console.log(`Searching for ${options.field}: ${options.value}`);
const response = await this.client.post('/public/search/regular', payload);
const result: SearchResult = {
data: response.data.data || [],
totalResults: parseInt(response.headers['x-rows-returned'] || '0'),
cost: parseInt(response.headers['x-charge'] || '0') / 1_000_000_000,
requestId: response.headers['x-request-id'] || 'unknown',
processingTime: parseInt(response.headers['x-processing-time'] || '0'),
};
console.log(`Found ${result.totalResults} records (Cost: $${result.cost.toFixed(6)})`);
return result;
} catch (error) {
console.error('Regular search failed:', error);
throw error;
}
}
async advancedSearch(queries: SearchOptions[]): Promise<SearchResult> {
try {
const payload = {
queries: queries.map(q => ({
field: q.field,
value: q.value,
option: q.option || 'exact',
})),
rowLimit: Math.min(queries[0]?.rowLimit || 1000, 10000),
};
console.log(`Advanced search with ${queries.length} queries`);
const response = await this.client.post('/public/search/advanced', payload);
const result: SearchResult = {
data: response.data.data || [],
totalResults: parseInt(response.headers['x-rows-returned'] || '0'),
cost: parseInt(response.headers['x-charge'] || '0') / 1_000_000_000,
requestId: response.headers['x-request-id'] || 'unknown',
processingTime: parseInt(response.headers['x-processing-time'] || '0'),
};
console.log(`Advanced search completed (Cost: $${result.cost.toFixed(6)})`);
return result;
} catch (error) {
console.error('Advanced search failed:', error);
throw error;
}
}
async getUsageStats(): Promise<UsageStats> {
try {
const response = await this.client.get('/public/usage/stats');
return response.data;
} catch (error) {
console.error('Failed to get usage stats:', error);
throw error;
}
}
analyzeBreaches(records: BreachRecord[]): {
breachDistribution: Record<string, number>;
dateDistribution: Record<string, number>;
totalRecords: number;
} {
const breachDistribution: Record<string, number> = {};
const dateDistribution: Record<string, number> = {};
records.forEach(record => {
const breachName = record.breach_name || 'Unknown';
breachDistribution[breachName] = (breachDistribution[breachName] || 0) + 1;
const breachDate = record.breach_date;
if (breachDate) {
const year = new Date(breachDate).getFullYear().toString();
dateDistribution[year] = (dateDistribution[year] || 0) + 1;
}
});
return {
breachDistribution,
dateDistribution,
totalRecords: records.length,
};
}
}
async function demonstrateUsage() {
const client = new LeakZeroClient(process.env.LEAKZERO_API_KEY!, {
maxRetries: 5,
timeout: 60000,
});
try {
console.log('Checking API balance...');
const balance = await client.getBalance();
console.log(`Current balance: $${balance.balance.toFixed(6)}`);
if (balance.balance < 0.001) {
throw new Error('Insufficient balance. Please top up your account.');
}
console.log('\nPerforming regular search...');
const emailSearch = await client.regularSearch({
field: 'email',
value: '[email protected]',
option: 'exact',
rowLimit: 100,
});
console.log(`Found ${emailSearch.totalResults} records for email search`);
if (emailSearch.data.length > 0) {
const analysis = client.analyzeBreaches(emailSearch.data);
console.log('\nBreach Analysis:');
console.log('Top breaches:',
Object.entries(analysis.breachDistribution)
.sort(([,a], [,b]) => b - a)
.slice(0, 5)
);
}
console.log('\nPerforming advanced search...');
const advancedSearch = await client.advancedSearch([
{ field: 'email', value: '[email protected]' },
{ field: 'username', value: 'johndoe' },
]);
console.log(`Advanced search found ${advancedSearch.totalResults} records`);
console.log('\nGetting usage statistics...');
const stats = await client.getUsageStats();
console.log('Usage stats:', stats);
} catch (error) {
if (error instanceof Error) {
console.error('Error:', error.message);
} else {
console.error('Unknown error:', error);
}
}
}
export { LeakZeroClient, type SearchOptions, type SearchResult, type BreachRecord };
if (require.main === module) {
demonstrateUsage();
}Type Safety: Full TypeScript interfaces for all API responses and requests
Error Handling: Comprehensive error handling with proper typing
Retry Logic: Smart retry mechanisms for production reliability
Key Features
TypeScript Benefits
- Compile-time type checking
- IntelliSense and autocomplete
- Refactoring safety
- Self-documenting interfaces
Production Features
- Exponential backoff retry
- Rate limit handling
- Request/response logging
- Built-in data analysis