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 --init
Note: 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
Documentation - LeakZero | LeakZero