Package Exports
- untamper-sdk
Readme
unTamper Node.js SDK
Official Node.js SDK for unTamper - Enterprise audit logging platform for secure, write-once-read-only audit logs.
Features
- ๐ Fast & Reliable: Optimized for high-performance log ingestion
- ๐ Type-Safe: Full TypeScript support with comprehensive type definitions
- ๐ Auto-Retry: Built-in retry logic with exponential backoff
- ๐ก๏ธ Error Handling: Comprehensive error handling with custom error classes
- ๐ฆ Zero Dependencies: Minimal footprint with no external runtime dependencies
- ๐งช Well Tested: Comprehensive test suite with 100% coverage
- ๐ง Developer Friendly: Easy configuration and debugging support
Installation
npm install @untamper/sdk-nodeQuick Start
import { UnTamperClient } from '@untamper/sdk-node';
// Initialize the client
const client = new UnTamperClient({
  projectId: 'your-project-id',
  apiKey: 'your-api-key',
  // For development, you can override the base URL
  baseUrl: 'http://localhost:3000',
});
// Log an audit event
const response = await client.logs.ingestLog({
  action: 'user.login',
  actor: {
    id: 'user123',
    type: 'user',
    display_name: 'John Doe',
  },
  result: 'SUCCESS',
  context: {
    request_id: 'req_123456',
    session_id: 'sess_789012',
  },
  metadata: {
    version: '1.0.0',
    environment: 'production',
  },
});
console.log('Log ingested:', response.ingestId);Configuration
Required Settings
- projectId: Your project identifier
- apiKey: Your project API key
Optional Settings
- baseUrl: API base URL (defaults to production, allows dev override)
- timeout: Request timeout in milliseconds (default: 30000)
- retryAttempts: Number of retry attempts (default: 3)
- retryDelay: Delay between retries in milliseconds (default: 1000)
const client = new UnTamperClient({
  projectId: 'your-project-id',
  apiKey: 'your-api-key',
  baseUrl: 'http://localhost:3000', // For development
  timeout: 10000,
  retryAttempts: 5,
  retryDelay: 2000,
});API Reference
Log Ingestion
client.logs.ingestLog(request)
Ingests a single audit log.
const response = await client.logs.ingestLog({
  action: 'document.update',
  actor: {
    id: 'user123',
    type: 'user',
    display_name: 'John Doe',
  },
  target: {
    id: 'doc456',
    type: 'document',
    display_name: 'Important Document',
  },
  result: 'SUCCESS',
  changes: [
    {
      path: 'title',
      old_value: 'Old Title',
      new_value: 'New Title',
    },
  ],
  context: {
    request_id: 'req_123',
    client: 'web-app',
  },
  metadata: {
    feature: 'document-editor',
    version: '2.1.0',
  },
});client.logs.ingestLogs(requests)
Ingests multiple audit logs in batch.
const responses = await client.logs.ingestLogs([
  { action: 'user.login', actor: { id: 'user1', type: 'user' } },
  { action: 'user.logout', actor: { id: 'user2', type: 'user' } },
]);client.logs.checkIngestionStatus(ingestId)
Checks the status of a previously submitted audit log.
const status = await client.logs.checkIngestionStatus('ingest_123');
console.log('Status:', status.status); // PENDING, PROCESSING, COMPLETED, FAILED, RETRYINGclient.logs.waitForCompletion(ingestId, options)
Waits for an ingestion to complete with polling.
const status = await client.logs.waitForCompletion('ingest_123', {
  pollInterval: 1000, // Check every 1 second
  maxWaitTime: 30000, // Wait up to 30 seconds
});Queue Management
client.queue.getQueueStats()
Gets queue statistics.
const stats = await client.queue.getQueueStats();
console.log('Total items:', stats.data?.total);
console.log('By status:', stats.data?.byStatus);client.queue.triggerQueueProcessing()
Triggers manual queue processing.
const result = await client.queue.triggerQueueProcessing();
console.log('Processing triggered:', result.message);Error Handling
The SDK provides comprehensive error handling with custom error classes:
import { 
  UnTamperError,
  AuthenticationError,
  ValidationError,
  NetworkError,
  RateLimitError,
  ServerError,
  ConfigurationError,
} from '@untamper/sdk-node';
try {
  await client.logs.ingestLog(request);
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Invalid request:', error.message, error.details);
  } else if (error instanceof AuthenticationError) {
    console.error('Authentication failed:', error.message);
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.message);
  } else if (error instanceof RateLimitError) {
    console.error('Rate limited:', error.message);
  } else if (error instanceof ServerError) {
    console.error('Server error:', error.message);
  } else if (error instanceof UnTamperError) {
    console.error('unTamper error:', error.message, error.code);
  } else {
    console.error('Unexpected error:', error);
  }
}TypeScript Support
The SDK is built with TypeScript and provides full type safety:
import { 
  UnTamperClient,
  LogIngestionRequest,
  LogIngestionResponse,
  Actor,
  Target,
  ActionResult,
} from '@untamper/sdk-node';
const request: LogIngestionRequest = {
  action: 'user.login',
  actor: {
    id: 'user123',
    type: 'user',
    display_name: 'John Doe',
  },
  result: 'SUCCESS' as ActionResult,
};Examples
Express.js Middleware
import express from 'express';
import { UnTamperClient } from '@untamper/sdk-node';
const client = new UnTamperClient({
  projectId: 'your-project-id',
  apiKey: 'your-api-key',
});
function auditLogMiddleware(req: express.Request, res: express.Response, next: express.NextFunction) {
  const originalSend = res.send;
  const startTime = Date.now();
  res.send = function(body: any) {
    const duration = Date.now() - startTime;
    
    // Log the request asynchronously
    client.logs.ingestLog({
      action: `${req.method.toLowerCase()}.${req.path}`,
      actor: {
        id: (req as any).user?.id || 'anonymous',
        type: (req as any).user ? 'user' : 'system',
      },
      result: res.statusCode < 400 ? 'SUCCESS' : 'FAILURE',
      context: {
        method: req.method,
        url: req.url,
        status_code: res.statusCode,
        duration_ms: duration,
      },
    }).catch(console.error);
    return originalSend.call(this, body);
  };
  next();
}
const app = express();
app.use(auditLogMiddleware);Batch Processing
// Process multiple events
const events = [
  { action: 'user.login', actor: { id: 'user1', type: 'user' } },
  { action: 'user.logout', actor: { id: 'user2', type: 'user' } },
  { action: 'document.create', actor: { id: 'user3', type: 'user' } },
];
const responses = await client.logs.ingestLogs(events);
console.log(`Processed ${responses.length} events`);
// Wait for all to complete
const statuses = await Promise.all(
  responses.map(response => 
    client.logs.waitForCompletion(response.ingestId!)
  )
);Development
Prerequisites
- Node.js 16.0.0 or higher
- npm or yarn
Setup
git clone https://github.com/untamper/sdk-node.git
cd sdk-node
npm installBuilding
npm run buildTesting
npm test
npm run test:coverageLinting
npm run lint
npm run lint:fixRequirements
- Node.js: 16.0.0 or higher
- TypeScript: 4.0 or higher (for TypeScript projects)
License
MIT License - see LICENSE file for details.
Support
- ๐ง Email: support@untamper.com
- ๐ Documentation: https://docs.untamper.com
- ๐ Issues: GitHub Issues
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Made with โค๏ธ by the unTamper team