Skip to main content

Overview

The SDK exports all TypeScript types for full type safety in your application.

Import

Web SDK:
import type {
  ClientOptions,
  TraceOptions,
  AddEventOptions,
  ChainName,
  Severity,
  Logger,
  ClientMetadata,
  TraceEvent,
  TxHashHint,
  SafeMsgHintData,
  SafeTxHintData,
  TxHintOptions,
  TransactionLike,
  TransactionRequest,
  EIP1193Provider,
  MiradorProviderOptions,
  StackFrame,
  StackTrace,
  TraceCallbacks,
  MiradorPlugin,
  TraceContext,
  PluginSetupResult,
  FlushBuilder,
  Web3Plugin,
  Web3Methods,
  EvmMethods,
  SafeNamespaceMethods,
  NoopTrace,
  HintType
} from '@miradorlabs/web-sdk';
Node.js SDK:
import type {
  ClientOptions,
  TraceOptions,
  AddEventOptions,
  ChainName,
  Severity,
  Logger,
  TraceEvent,
  TxHashHint,
  SafeMsgHintData,
  SafeTxHintData,
  TxHintOptions,
  TransactionLike,
  TransactionRequest,
  EIP1193Provider,
  MiradorProviderOptions,
  StackFrame,
  StackTrace,
  TraceCallbacks,
  MiradorPlugin,
  TraceContext,
  PluginSetupResult,
  FlushBuilder,
  Web3Plugin,
  Web3Methods,
  EvmMethods,
  SafeNamespaceMethods,
  NoopTrace,
  HintType
} from '@miradorlabs/nodejs-sdk';

ClientOptions

Configuration options for the client. Web SDK:
interface ClientOptions {
  /**
   * Gateway URL for the Mirador Ingest API
   * @default 'ingest.mirador.org:443'
   */
  apiUrl?: string;

  /**
   * Keep-alive ping interval in milliseconds
   * @default 10000
   */
  keepAliveIntervalMs?: number;

  /**
   * Timeout for individual API calls in milliseconds
   * @default 5000
   */
  callTimeoutMs?: number;

  /**
   * Maximum trace lifetime in milliseconds. When exceeded, the trace is automatically closed.
   * Set to 0 to disable.
   * @default 0
   */
  maxTraceLifetimeMs?: number;

  /**
   * Enable debug logging
   * @default false
   */
  debug?: boolean;

  /**
   * Custom logger implementation
   */
  logger?: Logger;

  /**
   * Lifecycle callbacks for all traces created by this client
   */
  callbacks?: TraceCallbacks;

  /**
   * Sample rate for traces (0 to 1). 0 = drop all, 1 = keep all.
   * Unsampled traces return a NoopTrace.
   * @default 1
   */
  sampleRate?: number;

  /**
   * Custom sampler function. Takes precedence over sampleRate.
   * Return true to keep the trace, false to drop it.
   */
  sampler?: (name: string | undefined, options: TraceOptions) => boolean;

  /**
   * Plugins to install on all traces created by this client.
   */
  plugins?: MiradorPlugin[];
}
Node.js SDK:
interface ClientOptions {
  /**
   * Gateway URL for the Mirador Ingest API
   * @default 'ingest.mirador.org:443'
   */
  apiUrl?: string;

  /**
   * Keep-alive ping interval in milliseconds
   * @default 10000
   */
  keepAliveIntervalMs?: number;

  /**
   * Timeout for individual API calls in milliseconds
   * @default 5000
   */
  callTimeoutMs?: number;

  /**
   * Maximum trace lifetime in milliseconds. When exceeded, the trace is automatically closed.
   * Set to 0 to disable.
   * @default 0
   */
  maxTraceLifetimeMs?: number;

  /**
   * Enable debug logging
   * @default false
   */
  debug?: boolean;

  /**
   * Custom logger implementation
   */
  logger?: Logger;

  /**
   * Lifecycle callbacks for all traces created by this client
   */
  callbacks?: TraceCallbacks;

  /**
   * Sample rate for traces (0 to 1). 0 = drop all, 1 = keep all.
   * Unsampled traces return a NoopTrace.
   * @default 1
   */
  sampleRate?: number;

  /**
   * Custom sampler function. Takes precedence over sampleRate.
   * Return true to keep the trace, false to drop it.
   */
  sampler?: (name: string | undefined, options: TraceOptions) => boolean;

  /**
   * Plugins to install on all traces created by this client.
   */
  plugins?: MiradorPlugin[];

  /**
   * Use SSL for the gRPC connection
   * @default true
   */
  useSsl?: boolean;
}

Usage

const options: ClientOptions = {
  apiUrl: 'https://custom-gateway.example.com:443'
};

const client = new Client('api-key', options);
With Web3Plugin:
import { Client, Web3Plugin } from '@miradorlabs/web-sdk';

const client = new Client('api-key', {
  plugins: [Web3Plugin({ provider: window.ethereum })]
});

// All traces created by this client will have web3 methods available
Node.js SDK — local development (no SSL):
const client = new Client('api-key', {
  apiUrl: 'localhost:50053',
  useSsl: false
});

TraceOptions

Configuration options for individual traces. Web SDK:
interface TraceOptions {
  /**
   * Name identifying the trace
   */
  name?: string;

  /**
   * Resume an existing trace by ID, or provide a pre-generated W3C Tracing Context
   * compatible ID (32-char hex string).
   * When set, the flush uses the provided ID instead of generating a new one.
   */
  traceId?: string;

  /**
   * Include browser metadata on first flush
   * @default true
   */
  includeUserMeta?: boolean;

  /**
   * Maximum retry attempts on network failure
   * @default 2
   */
  maxRetries?: number;

  /**
   * Base delay in ms for exponential backoff
   * @default 500
   */
  retryBackoff?: number;

  /**
   * Automatically close trace on page unload
   * @default false
   */
  autoClose?: boolean;

  /**
   * Automatically start the keep-alive timer.
   * Defaults to true for new traces, false when traceId is set (resumed traces).
   */
  autoKeepAlive?: boolean;

  /**
   * Maximum number of events/items in the flush queue before dropping.
   * @default 4096
   */
  maxQueueSize?: number;

  /**
   * Lifecycle callbacks for this specific trace (merged with client-level callbacks).
   */
  callbacks?: TraceCallbacks;
}
Node.js SDK:
interface TraceOptions {
  /**
   * Name identifying the trace
   */
  name?: string;

  /**
   * Resume an existing trace by ID, or provide a pre-generated W3C Tracing Context
   * compatible ID (32-char hex string).
   * When set, the flush uses the provided ID instead of generating a new one.
   */
  traceId?: string;

  /**
   * Capture stack trace at trace creation point
   * @default true
   */
  captureStackTrace?: boolean;

  /**
   * Maximum retry attempts on network failure
   * @default 2
   */
  maxRetries?: number;

  /**
   * Base delay in ms for exponential backoff
   * @default 500
   */
  retryBackoff?: number;

  /**
   * Automatically start the keep-alive timer.
   * Defaults to true for new traces, false when traceId is set (resumed traces).
   */
  autoKeepAlive?: boolean;

  /**
   * Maximum number of events/items in the flush queue before dropping.
   * @default 4096
   */
  maxQueueSize?: number;

  /**
   * Lifecycle callbacks for this specific trace (merged with client-level callbacks).
   */
  callbacks?: TraceCallbacks;
}

Usage

Web SDK:
const options: TraceOptions = {
  name: 'MyTrace',
  includeUserMeta: true,
  maxRetries: 5,
  retryBackoff: 1000
};

const trace = client.trace(options);
Node.js SDK:
const options: TraceOptions = {
  name: 'MyTrace',
  captureStackTrace: false
};

const trace = client.trace(options);
Node.js SDK — Resuming a frontend trace:
// Backend receives trace ID from frontend (e.g., via HTTP header)
const trace = client.trace({
  name: 'BackendProcessing',
  traceId: req.headers['x-mirador-trace-id']
});

trace.addEvent('backend:received');
// → FlushTrace sent automatically (uses the provided traceId)

TraceCallbacks

Lifecycle callbacks for observing trace events programmatically. See the Lifecycle Callbacks guide for detailed usage patterns.
interface TraceCallbacks {
  /** Called once when the trace is first created on the server (first successful flush) */
  onCreated?: (traceId: string) => void;

  /** Called after each successful flush */
  onFlushed?: (traceId: string, itemCount: number) => void;

  /** Called when a flush operation fails after retries */
  onFlushError?: (error: Error, operation: string) => void;

  /** Called when the trace is closed */
  onClosed?: (traceId: string, reason?: string) => void;

  /** Called when items are dropped (e.g., queue full) */
  onDropped?: (count: number, reason: string) => void;
}

Usage

const client = new Client('api-key', {
  callbacks: {
    onCreated: (traceId) => console.log('Trace created:', traceId),
    onFlushed: (traceId, itemCount) => console.log(`Flushed ${itemCount} items`),
    onFlushError: (error, operation) => console.error(`${operation} failed:`, error),
    onClosed: (traceId, reason) => console.log('Closed:', traceId, reason),
    onDropped: (count, reason) => console.warn(`Dropped ${count} items: ${reason}`)
  }
});

Logger

Interface for custom logging implementations. See the Custom Logging guide for integration examples.
interface Logger {
  debug(...args: unknown[]): void;
  warn(...args: unknown[]): void;
  error(...args: unknown[]): void;
}

Usage

// Use the built-in console logger
const client = new Client('api-key', { debug: true });

// Or provide a custom logger
const client = new Client('api-key', {
  logger: {
    debug: (...args) => myLogger.debug(args.join(' ')),
    warn:  (...args) => myLogger.warn(args.join(' ')),
    error: (...args) => myLogger.error(args.join(' '))
  }
});

Severity

Event severity levels used by convenience methods.
type Severity = 'info' | 'warn' | 'error';

Usage

trace.info('User action completed');
trace.warn('Approaching rate limit');
trace.error('Transaction failed', { code: 'REVERT' });

MiradorPlugin

Interface for creating plugins that extend trace functionality.
interface MiradorPlugin {
  /** Unique plugin name — used as the namespace on the trace */
  name: string;

  /** Called when a trace is created. Returns methods and lifecycle hooks. */
  setup(context: TraceContext): PluginSetupResult;
}

TraceContext

Read/write access to the trace, passed to plugin setup().
interface TraceContext {
  /** Add an event to the trace */
  addEvent(name: string, details?: string | object, options?: AddEventOptions): void;
  /** Add a single attribute */
  addAttribute(key: string, value: string | number | boolean | object): void;
  /** Add multiple attributes at once */
  addAttributes(attrs: Record<string, string | number | boolean | object>): void;
  /** Add a single tag */
  addTag(tag: string): void;
  /** Add multiple tags at once */
  addTags(tags: string[]): void;
  /** Get the W3C trace ID */
  getTraceId(): string;
  /** Check if the trace has been closed */
  isClosed(): boolean;
  /** Schedule a flush (batched via microtask) */
  scheduleFlush(): void;
  /** Logger instance respecting client configuration */
  logger: Logger;
}

PluginSetupResult

Object returned by a plugin’s setup() method.
interface PluginSetupResult<TMethods> {
  /** Methods to merge onto the Trace instance under the plugin's name */
  methods: TMethods;

  /** No-op versions of methods for NoopTrace (sampled-out traces).
   *  If not provided, methods default to returning `this` for chaining. */
  noopMethods?: DeepPartial<TMethods>;

  /** Called during flush to contribute data to the payload */
  onFlush?: (builder: FlushBuilder) => void;

  /** Called when the trace is being closed */
  onClose?: () => void;

  /** Return true if this plugin has unflushed data */
  hasPendingData?: () => boolean;
}

FlushBuilder

Interface for contributing data to a flush payload from a plugin’s onFlush hook.
interface FlushBuilder {
  /** Add a hint (type-safe for known hint types) */
  addHint<T extends HintTypeName>(type: T, data: HintDataMap[T]): void;
  /** Add a hint with a custom type (extensibility fallback) */
  addHint(type: string, data: Record<string, unknown>): void;
  /** Add an event to the flush payload */
  addEvent(event: { name: string; details?: string; timestamp: Date; severity?: Severity }): void;
  /** Add an attribute */
  addAttribute(key: string, value: string): void;
  /** Add a tag */
  addTag(tag: string): void;
}

Web3Methods

Methods available on trace.web3 when using the Web3Plugin.
interface Web3Methods {
  evm: EvmMethods;
  safe: SafeNamespaceMethods;
}

EvmMethods

EVM transaction methods available on trace.web3.evm.
interface EvmMethods {
  addTxHint(txHash: string, chain: ChainName, options?: string | TxHintOptions): Trace;
  addTxInputData(inputData: string): Trace;
  addTx(tx: TransactionLike, chain?: ChainName): Trace;
  sendTransaction(tx: TransactionRequest): Promise<string>;
}

SafeNamespaceMethods

Safe multisig methods available on trace.web3.safe.
interface SafeNamespaceMethods {
  addMsgHint(msgHint: string, chain: ChainName, details?: string): Trace;
  addTxHint(safeTxHash: string, chain: ChainName, details?: string): Trace;
}

NoopTrace

A trace implementation that silently discards all operations. Returned when a trace is not sampled.
class NoopTrace {
  // All Trace methods are available but do nothing
  addAttribute(key: string, value: any): NoopTrace;
  addEvent(name: string, details?: any): NoopTrace;
  getTraceId(): string;  // Returns the generated ID
  // ... etc
}

Usage

const client = new Client('api-key', { sampleRate: 0.5 });
const trace = client.trace({ name: 'MaybeRecorded' });

// Safe to call all methods — if unsampled, they're silently ignored
trace.addEvent('action');

HintType

Discriminator for the type of transaction hint.
type HintType = 'tx' | 'safe_msg' | 'safe_tx';

ChainName

Supported blockchain networks for transaction hints.
type ChainName =
  | 'ethereum'
  | 'polygon'
  | 'arbitrum'
  | 'base'
  | 'optimism'
  | 'bsc';

Usage

const chain: ChainName = 'ethereum';
trace.web3.evm.addTxHint(txHash, chain);

// Type-safe: only valid chains allowed
trace.web3.evm.addTxHint(hash, 'polygon');   // OK
trace.web3.evm.addTxHint(hash, 'invalid');   // Type error

TraceEvent

Structure of events added to traces.
interface TraceEvent {
  /**
   * Event name
   */
  eventName: string;

  /**
   * Optional event details (stringified if object)
   */
  details?: string;

  /**
   * Timestamp of the event
   */
  timestamp: Date;
}

Usage

// Events are created internally by addEvent()
trace.addEvent('my_event', { key: 'value' });

// The SDK creates a TraceEvent like:
// {
//   eventName: 'my_event',
//   details: '{"key":"value"}',
//   timestamp: new Date()
// }

TxHashHint

Structure of blockchain transaction hints.
interface TxHashHint {
  /**
   * Transaction hash
   */
  txHash: string;

  /**
   * Blockchain network
   */
  chain: ChainName;

  /**
   * Optional description
   */
  details?: string;

  /**
   * Timestamp of the hint
   */
  timestamp: Date;
}

Usage

// TxHashHints are created internally by web3.evm.addTxHint()
trace.web3.evm.addTxHint('0x123...', 'ethereum', 'Swap transaction');

SafeMsgHintData

Structure of Safe multisig message hints.
interface SafeMsgHintData {
  /**
   * Safe message hash
   */
  messageHash: string;

  /**
   * Blockchain network the Safe is deployed on
   */
  chain: ChainName;

  /**
   * Optional description
   */
  details?: string;

  /**
   * Timestamp of the hint
   */
  timestamp: Date;
}

Usage

// SafeMsgHintData is created internally by web3.safe.addMsgHint()
trace.web3.safe.addMsgHint('0xabc...', 'ethereum', 'Multisig approval');

SafeTxHintData

Structure of Safe multisig transaction hints.
interface SafeTxHintData {
  /**
   * Safe transaction hash
   */
  safeTxHash: string;

  /**
   * Blockchain network the Safe is deployed on
   */
  chain: ChainName;

  /**
   * Optional description
   */
  details?: string;

  /**
   * Timestamp of the hint
   */
  timestamp: Date;
}

Usage

// SafeTxHintData is created internally by web3.safe.addTxHint()
trace.web3.safe.addTxHint('0xdef...', 'ethereum', 'Safe execution');

AddEventOptions

Options for the addEvent() method.
interface AddEventOptions {
  /**
   * Capture stack trace at event location
   * @default false
   */
  captureStackTrace?: boolean;

  /**
   * Custom timestamp for the event
   */
  timestamp?: Date;
}

Usage

// Capture stack trace for debugging
trace.addEvent('error_occurred', { code: 500 }, { captureStackTrace: true });

// Custom timestamp
trace.addEvent('operation_started', null, { timestamp: new Date('2024-01-01') });

StackFrame

Represents a single frame in a stack trace.
interface StackFrame {
  /**
   * Function name (or '<anonymous>')
   */
  functionName: string;

  /**
   * File name or URL
   */
  fileName: string;

  /**
   * Line number
   */
  lineNumber: number;

  /**
   * Column number
   */
  columnNumber: number;
}

StackTrace

Captured stack trace information.
interface StackTrace {
  /**
   * Parsed stack frames
   */
  frames: StackFrame[];

  /**
   * Original Error.stack string
   */
  raw: string;
}

Usage

import { captureStackTrace, formatStackTrace } from '@miradorlabs/web-sdk';

// Capture current stack trace
const stack = captureStackTrace();

// Format for storage
const json = formatStackTrace(stack);

// Format for display
const readable = formatStackTraceReadable(stack);

ClientMetadata (Web SDK Only)

Browser environment metadata collected automatically.
interface ClientMetadata {
  // Browser
  browser?: string;
  browserVersion?: string;
  userAgent?: string;

  // Operating System
  os?: string;
  osVersion?: string;
  deviceType?: string;

  // Display
  screenWidth?: string;
  screenHeight?: string;
  viewportWidth?: string;
  viewportHeight?: string;
  colorDepth?: string;
  pixelRatio?: string;

  // Hardware
  cpuCores?: string;
  deviceMemory?: string;
  touchSupport?: string;

  // Network
  connectionType?: string;
  online?: string;

  // Locale
  language?: string;
  languages?: string;
  timezone?: string;
  timezoneOffset?: string;

  // Page Context
  url?: string;
  origin?: string;
  pathname?: string;
  referrer?: string;
  documentVisibility?: string;

  // Privacy
  cookiesEnabled?: string;
  doNotTrack?: string;
}

Usage

import { getClientMetadata } from '@miradorlabs/web-sdk';

const metadata: ClientMetadata = getClientMetadata();
console.log(metadata.browser);      // 'Chrome'
console.log(metadata.deviceType);   // 'desktop'

EIP1193Provider

Standard EIP-1193 provider interface. Compatible with MetaMask, WalletConnect, and any EIP-1193 compliant wallet.
interface EIP1193Provider {
  request(args: { method: string; params?: unknown[] }): Promise<unknown>;
}

Usage

// window.ethereum is an EIP1193Provider
const provider: EIP1193Provider = window.ethereum;

// viem walletClient.transport is compatible
// ethers.js BrowserProvider is compatible

TxHintOptions

Structured options for web3.evm.addTxHint(), extending the simple string details.
interface TxHintOptions {
  /** Transaction input data / calldata */
  input?: string;
  /** Additional details string */
  details?: string;
}
When input is provided, it is emitted as a "Tx input data" event via web3.evm.addTxInputData(). Only details is stored in the hint itself.

Usage

// Simple string details
trace.web3.evm.addTxHint(txHash, 'ethereum', 'Swap transaction');

// Structured options with calldata
trace.web3.evm.addTxHint(txHash, 'ethereum', {
  input: '0xa9059cbb000000000000000000000000...',
  details: 'ERC-20 transfer'
});

TransactionLike

A transaction-like object that matches common library shapes (ethers v5/v6, viem, raw RPC).
interface TransactionLike {
  /** Transaction hash */
  hash: string;
  /** Transaction input data (ethers v5 style) */
  data?: string;
  /** Transaction input data (ethers v6 / viem / raw RPC style) */
  input?: string;
  /** Chain ID */
  chainId?: number | bigint | string;
}

Usage

// Works with ethers v5 TransactionResponse
const tx = await signer.sendTransaction(txData);
trace.web3.evm.addTx(tx); // tx.hash and tx.data are used

// Works with viem transaction objects
const hash = await walletClient.sendTransaction(request);
trace.web3.evm.addTx({ hash, input: request.data, chainId: request.chain.id });

TransactionRequest

Transaction parameters for web3.evm.sendTransaction(), matching the EIP-1193 eth_sendTransaction format.
interface TransactionRequest {
  /** Sender address */
  from: string;
  /** Recipient address */
  to?: string;
  /** Transaction input data / calldata */
  data?: string;
  /** Value in wei */
  value?: string | bigint;
  /** Gas limit */
  gas?: string | bigint;
  /** Gas price (legacy) */
  gasPrice?: string | bigint;
  /** Max fee per gas (EIP-1559) */
  maxFeePerGas?: string | bigint;
  /** Max priority fee per gas (EIP-1559) */
  maxPriorityFeePerGas?: string | bigint;
  /** Transaction nonce */
  nonce?: number | string;
  /** Chain ID */
  chainId?: number | string;
}

Usage

const tx: TransactionRequest = {
  from: '0xabc...',
  to: '0xdef...',
  data: '0xa9059cbb...',
  value: '0x0',
  chainId: 1
};

const txHash = await trace.web3.evm.sendTransaction(tx);

MiradorProviderOptions

Configuration for the MiradorProvider wrapper.
interface MiradorProviderOptions {
  /** Bind to an existing trace instead of auto-creating per transaction */
  trace?: Trace;
  /** Trace options for auto-created traces (ignored if trace is provided) */
  traceOptions?: TraceOptions;
}

Usage

import { Client, MiradorProvider } from '@miradorlabs/web-sdk';

const client = new Client('api-key');

// Auto-create a new trace per transaction
const provider = new MiradorProvider(window.ethereum, client);

// Or bind to an existing trace
const trace = client.trace({ name: 'MyFlow' });
const provider = new MiradorProvider(window.ethereum, client, { trace });

Utility Functions

Both SDKs export utility functions for stack traces and chain ID mapping. The Web SDK additionally exports browser metadata utilities. Both SDKs:
import {
  captureStackTrace,
  formatStackTrace,
  formatStackTraceReadable,
  chainIdToName
} from '@miradorlabs/web-sdk'; // or '@miradorlabs/nodejs-sdk'

// Capture current stack trace
const stack = captureStackTrace();

// Format for storage (JSON)
const json = formatStackTrace(stack);

// Format for display (human-readable)
const readable = formatStackTraceReadable(stack);

// Convert chain ID to chain name
chainIdToName(1);     // 'ethereum'
chainIdToName(137);   // 'polygon'
chainIdToName(42161); // 'arbitrum'
chainIdToName(8453);  // 'base'
chainIdToName(10);    // 'optimism'
chainIdToName(56);    // 'bsc'
chainIdToName(999);   // undefined
Web SDK only — browser metadata:
import {
  getClientMetadata,
  detectBrowser,
  detectOS,
  detectDeviceType,
} from '@miradorlabs/web-sdk';

// Get full metadata object
const metadata = getClientMetadata();

// Individual detection
const browser = detectBrowser();
// { name: 'Chrome', version: '120.0.0' }

const os = detectOS();
// { name: 'macOS', version: '14.0' }

const device = detectDeviceType();
// 'desktop' | 'mobile' | 'tablet'

Next Steps

Client

Client class reference

Trace

Trace builder reference