@miradorlabs/web-sdk
v2.0.0
Published
Mirador Client Side Web SDK
Readme
Mirador Web Client SDK
Web browser SDK for the Mirador tracing platform. This package provides a browser-compatible client using gRPC-Web to interact with the Mirador Ingest Gateway API.
Installation
npm install @miradorlabs/web-sdkFeatures
- Keep-Alive - Automatic periodic pings with in-flight guard, single retry, and auto-stop after 3 consecutive failures
- Trace Lifecycle - Explicit close trace method with automatic cleanup and flush queue draining
- Fluent Builder Pattern - Method chaining for building traces
- Browser-optimized - Automatic client metadata collection (browser, OS, etc.)
- Blockchain Integration - Built-in support for correlating traces with blockchain transactions
- Stack Trace Capture - Automatic or manual capture of call stack for debugging
- TypeScript Support - Full type definitions included
- Strict Ordering - Flush calls maintain strict ordering even when async
- Cross-SDK Trace Sharing - Resume traces across frontend and backend SDKs
- Safe Multisig Tracking - Track Safe message and transaction confirmations via
web3.safe.addMsgHint()andweb3.safe.addTxHint() - EIP-1193 Provider Integration - Send transactions directly through traces with
sendTransaction() - Configurable Logger - Pluggable
Loggerinterface (defaults to no-op; enable withdebug: trueor provide custom logger) - Lifecycle Callbacks -
TraceCallbacksfor observing flush success/failure, close, and dropped items - Sampling -
sampleRate(0–1) or customsamplerfunction; sampled-out traces returnNoopTrace - Rate Limiting - Automatic 30s client-wide backoff on
RESOURCE_EXHAUSTED(gRPC code 8) - Retry with Jitter - Full jitter backoff (
random(0, base * 2^attempt)) on retryable gRPC errors - Queue Size Limits - Configurable
maxQueueSize(default 4096) withonDroppedcallback - Flush Batch Splitting - Large flushes automatically split at 100 items with overflow re-scheduling
- Trace Abandonment - After retry exhaustion, trace stops all API calls to prevent runaway retries
- Max Trace Lifetime - Optional
maxTraceLifetimeMsto auto-close long-running traces - Call Timeout - Per-call
callTimeoutMs(default 5000ms) wrapping all gRPC operations
Quick Start (Default)
import { Client } from '@miradorlabs/web-sdk';
const client = new Client('your-api-key');
const trace = client.trace({ name: 'SwapExecution' })
.addAttribute('from', '0xabc...')
.addTags(['dex', 'swap'])
.info('quote_received');
// → FlushTrace sent after 50ms of inactivity
trace.info('transaction_signed')
.web3.evm.addTxHint('0xtxhash...', 'ethereum');
// → FlushTrace sent after 50ms of inactivity
// You can still call flush() explicitly to send immediately
trace.info('confirmed');
trace.flush(); // → FlushTrace sent immediatelyManual Flush Mode
import { Client } from '@miradorlabs/web-sdk';
const client = new Client('your-api-key');
const trace = client.trace({ name: 'SwapExecution', })
.addAttribute('from', '0xabc...')
.addTags(['dex', 'swap'])
.info('quote_received');
trace.flush(); // → FlushTrace
trace.info('transaction_signed')
.web3.evm.addTxHint('0xtxhash...', 'ethereum');
trace.flush(); // → FlushTraceKeep-Alive & Trace Lifecycle
Automatic Keep-Alive
The SDK automatically sends keep-alive pings to the server every 10 seconds (configurable) to maintain trace liveness. This starts automatically after the first successful trace creation.
// Use default 10-second interval
const client = new Client('your-api-key');
// Or customize the interval
const client = new Client('your-api-key', {
keepAliveIntervalMs: 15000 // Ping every 15 seconds
});
const trace = client.trace({ name: 'MyTrace' });
// Keep-alive starts automatically after first flush completesClosing Traces
Always close traces when you're done to clean up resources and notify the server:
const trace = client.trace({ name: 'UserSession' });
// ... add events, attributes, etc ...
// Close when done
await trace.close('Session ended');
// All subsequent operations are ignored
trace.info('ignored'); // Logs warning, does nothingBest Practices:
- Always call
close()when you're done with a trace - Use try-catch blocks to ensure traces are closed even on errors
- Provide a meaningful reason to help with debugging
const trace = client.trace({ name: 'CheckoutFlow' });
try {
// ... trace user checkout flow ...
await trace.close('Checkout completed');
} catch (error) {
trace.error('error', { message: error.message });
await trace.close('Checkout failed');
}Auto-Close on Page Visibility Change
For browser-based applications, you can enable automatic trace closing when the page becomes hidden:
const trace = client.trace({
name: 'UserSession',
autoClose: true // Automatically close when page becomes hidden
});
// Trace will automatically close with reason "Page hidden" when:
// - User switches to a different tab
// - User minimizes the browser
// - User navigates to a different page
// - User closes the tab/windowImportant Notes:
- Auto-close uses the
visibilitychangeevent ondocument - The trace will be closed with the reason "Page hidden"
- You can still manually call
close()before the page becomes hidden - The event listener is automatically cleaned up when you manually close the trace
API Reference
Client
The main client for interacting with the Mirador Ingest Gateway.
Constructor
new Client(apiKey: string, options?: ClientOptions)| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| apiKey | string | Yes | API key for authentication (sent as x-ingest-api-key header) |
| options | ClientOptions | No | Configuration options |
Options
interface ClientOptions {
apiUrl?: string; // Gateway URL (defaults to https://ingest.mirador.org:443)
keepAliveIntervalMs?: number; // Keep-alive ping interval in milliseconds (default: 10000)
provider?: EIP1193Provider; // EIP-1193 provider for transaction operations
callTimeoutMs?: number; // Per-call timeout for gRPC operations (default: 5000)
debug?: boolean; // Enable debug logging via console (default: false)
logger?: Logger; // Custom logger implementation (defaults to no-op)
callbacks?: TraceCallbacks; // Default lifecycle callbacks for all traces
sampleRate?: number; // Sample rate 0–1 (default: 1 = send all)
sampler?: (options: TraceOptions) => boolean; // Custom sampler (overrides sampleRate)
}Methods
trace(options?)
Creates a new trace builder.
const trace = client.trace({ name: 'MyTrace' });
const trace = client.trace({ name: 'MyTrace', });
// Stack trace capture is enabled by default - to disable:
const trace = client.trace({ name: 'MyTrace', captureStackTrace: false });| Option | Type | Default | Description |
|--------|------|---------|-------------|
| name | string | undefined | Optional name of the trace |
| traceId | string | auto-generated | Resume an existing trace by ID, or auto-generated W3C trace ID (32 hex chars) |
| includeUserMeta | boolean | true | Include browser/OS metadata |
| maxRetries | number | 2 | Maximum retry attempts on retryable gRPC errors |
| retryBackoff | number | 500 | Base delay in ms for full jitter backoff |
| autoClose | boolean | false | Automatically close trace on page visibility change |
| provider | EIP1193Provider | undefined | EIP-1193 provider for transaction operations |
| autoKeepAlive | boolean | true/false | Auto keep-alive (default: true for new, false when resuming) |
| maxTraceLifetimeMs | number | 0 | Max trace lifetime in ms (0 = disabled). Auto-closes trace after this duration |
| maxQueueSize | number | 4096 | Max pending items before dropping |
| callbacks | TraceCallbacks | undefined | Per-trace lifecycle callbacks (overrides client-level) |
Note: A W3C-compatible trace ID (32 hex chars) is automatically generated when you call
client.trace(). If you passtraceId, the trace resumes an existing trace instead.
Returns: Trace builder instance
Trace (Builder)
Fluent builder for constructing traces. All builder methods return this for chaining.
addAttribute(key, value)
Add a single attribute. Objects are automatically stringified.
trace.addAttribute('user', '0xabc...')
.addAttribute('amount', 1.5)
.addAttribute('config', { slippage: 50, deadline: 300 }) // stringified to JSONaddAttributes(attrs)
Add multiple attributes at once. Objects are automatically stringified.
trace.addAttributes({
from: '0xabc...',
to: '0xdef...',
value: 1.0,
metadata: { source: 'web', version: '1.0' } // stringified to JSON
})addTag(tag) / addTags(tags)
Add tags to categorize the trace.
trace.addTag('transaction')
.addTags(['ethereum', 'send'])info(name, details?, options?) / warn(...) / error(...)
Record an event with the corresponding severity level. All three share the same signature.
trace.info('wallet_connected', { wallet: 'MetaMask' })
.info('transaction_initiated')
.info('transaction_confirmed', { blockNumber: 12345 })
trace.warn('rate_limit', 'approaching limit')
trace.error('processing_failed', { code: 500 })
// With stack trace capture
trace.error('crash', { code: 500 }, { captureStackTrace: true })| Parameter | Type | Description |
|-----------|--------------------|--------------------------------------------------|
| name | string | Event name |
| details | string \| object | Optional event details (objects are stringified) |
| options | object | Optional settings (e.g. { captureStackTrace: true }) |
addEvent(name, details?, options?)
Low-level event method. Prefer info(), warning(), error() for clarity.
trace.addEvent('custom_event', 'details', { severity: Severity.Warn })
// Legacy: timestamp can still be passed as third parameter for backward compatibility
trace.addEvent('custom_event', 'details', new Date())addStackTrace(eventName?, additionalDetails?)
Capture and add the current stack trace as an event. Useful for debugging or tracking code paths.
trace.addStackTrace() // Creates event named "stack_trace"
trace.addStackTrace('checkpoint', { stage: 'validation' })| Parameter | Type | Description |
|---------------------|----------|--------------------------------------------------|
| eventName | string | Event name (defaults to "stack_trace") |
| additionalDetails | object | Optional additional details to include |
addExistingStackTrace(stackTrace, eventName?, additionalDetails?)
Add a previously captured stack trace as an event. Useful when you need to capture a stack trace at one point but record it later.
import { captureStackTrace } from '@miradorlabs/web-sdk';
// Capture stack trace now
const stack = captureStackTrace();
// ... later ...
trace.addExistingStackTrace(stack, 'deferred_location', { reason: 'async operation' })| Parameter | Type | Description |
|---------------------|--------------|--------------------------------------------------|
| stackTrace | StackTrace | Previously captured stack trace |
| eventName | string | Event name (defaults to "stack_trace") |
| additionalDetails | object | Optional additional details to include |
Web3Plugin Methods
The following methods are available when Web3Plugin is registered. They are accessed via the web3.evm and web3.safe namespaces on the trace.
web3.evm.addTxHint(txHash, chain, options?)
Add a transaction hash hint for blockchain correlation. Accepts Chain enum or chain name string.
import { Chain } from '@miradorlabs/web-sdk';
trace.web3.evm.addTxHint('0x123...', Chain.Ethereum, 'Main transaction');
trace.web3.evm.addTxHint('0x456...', 'polygon', 'Bridge transaction'); // string also works| Parameter | Type | Description |
|-----------|------|-------------|
| txHash | string | Transaction hash |
| chain | Chain \| ChainName | Chain enum value or name string |
| options | string \| TxHintOptions | Optional details string, or options with input and details |
web3.safe.addMsgHint(msgHash, chain, details?)
Add a Safe message hint for tracking Safe multisig message confirmations.
trace.web3.safe.addMsgHint('0xmsgHash...', Chain.Ethereum);
trace.web3.safe.addMsgHint('0xotherHash...', Chain.Base, 'Token approval');web3.safe.addTxHint(safeTxHash, chain, details?)
Add a Safe transaction hint for tracking Safe multisig transaction executions.
trace.web3.safe.addTxHint('0xsafeTxHash...', Chain.Ethereum);
trace.web3.safe.addTxHint('0xotherHash...', Chain.Base, 'Token transfer');web3.evm.addTx(tx, chain?)
Add a transaction object, automatically extracting hash, chain, and input data.
const tx = await signer.sendTransaction({ to, data });
trace.web3.evm.addTx(tx, Chain.Ethereum);
// Chain inferred from tx.chainId if not provided
trace.web3.evm.addTx({ hash: txHash, data: calldata, chainId: 1 });web3.evm.sendTransaction(tx, provider?)
Send a transaction through the trace's EIP-1193 provider, automatically capturing events (tx:send, tx:sent, tx:error), input data, and tx hint.
const client = new Client('key', { plugins: [Web3Plugin({ provider: window.ethereum })] });
const trace = client.trace({ name: 'Swap' });
const txHash = await trace.web3.evm.sendTransaction({
from: '0xabc...',
to: '0xRouterAddress...',
data: '0x38ed1739...',
});web3.evm.setProvider(provider)
Set an EIP-1193 provider for transaction operations. Automatically detects chain ID.
trace.web3.evm.setProvider(window.ethereum);web3.evm.addInputData(inputData)
Add transaction input data (calldata) as a trace event.
trace.web3.evm.addInputData('0xa9059cbb000000000000000000000000...')flush()
Flush pending data to the gateway. Fire-and-forget - returns immediately but maintains strict ordering.
Each flush sends FlushTrace (an idempotent create-or-update RPC).
trace.flush();Returns: void
getTraceId()
Get the trace ID. Always available immediately since trace IDs are generated at client.trace() time.
const traceId = trace.getTraceId(); // stringReturns: string
close(reason?)
Close the trace and stop all timers (flush timer and keep-alive timer). After calling this method, all subsequent operations will be ignored.
await trace.close();
await trace.close('User completed workflow');| Parameter | Type | Description |
|-----------|------|-------------|
| reason | string | Optional reason for closing the trace |
Returns: Promise<void>
Important: Once a trace is closed:
- All method calls (
addAttribute,addEvent,addTag,web3.evm.addTxHint,web3.safe.addMsgHint,web3.safe.addTxHint,flush) will be ignored with a warning - The keep-alive timer will be stopped
- A close request will be sent to the server
isClosed()
Check if the trace has been closed.
const closed = trace.isClosed(); // booleanLogger
By default, the SDK silences all log output. Enable logging with debug: true for console output, or provide a custom Logger:
// Debug mode — logs to console.debug/warn/error
const client = new Client('key', { debug: true });
// Custom logger
const client = new Client('key', {
logger: {
debug: (...args) => myLogger.debug(...args),
warn: (...args) => myLogger.warn(...args),
error: (...args) => myLogger.error(...args),
},
});Lifecycle Callbacks (TraceCallbacks)
Observe trace lifecycle events programmatically:
const client = new Client('key', {
callbacks: {
onFlushed: (traceId, itemCount) => console.log(`Flushed ${itemCount} items`),
onFlushError: (error, operation) => console.error(`${operation} failed:`, error),
onClosed: (traceId, reason) => console.log(`Trace closed: ${reason}`),
onDropped: (count, reason) => console.warn(`Dropped ${count} items: ${reason}`),
},
});
// Per-trace overrides
const trace = client.trace({
name: 'ImportantFlow',
callbacks: { onFlushed: (id, n) => analytics.track('flush', { id, n }) },
});Sampling
Control which traces are actually sent:
// Fixed sample rate — send 10% of traces
const client = new Client('key', { sampleRate: 0.1 });
// Custom sampler — full control
const client = new Client('key', {
sampler: (options) => {
// Always sample traces named "critical"
if (options.name === 'critical') return true;
return Math.random() < 0.1;
},
});When a trace is sampled out, client.trace() returns a NoopTrace — a zero-cost stub with the same API surface. All method calls are no-ops, and getTraceId() returns a sentinel value ('0'.repeat(32)).
import { NoopTrace } from '@miradorlabs/web-sdk';
const trace = client.trace({ name: 'MaybeSampled' });
if (trace instanceof NoopTrace) {
// This trace was sampled out — no network calls will be made
}Complete Example: Transaction Tracking
import { Client } from '@miradorlabs/web-sdk';
// Create client with custom keep-alive interval (optional)
const client = new Client('your-api-key', {
keepAliveIntervalMs: 15000 // Override default 10s interval
});
async function handleWalletTransaction(userAddress: string, recipientAddress: string, amount: string) {
const trace = client.trace({ name: 'SendETH' })
.addAttribute('from', userAddress)
.addAttribute('to', recipientAddress)
.addAttribute('value', amount)
.addTags(['transaction', 'send', 'ethereum'])
.info('wallet_connected', { wallet: 'MetaMask' });
// → FlushTrace sent automatically
// → Keep-alive timer starts automatically
trace.info('user_signed');
try {
const receipt = await sendTransaction();
trace.info('transaction_sent', { txHash: receipt.hash })
.web3.evm.addTxHint(receipt.hash, 'ethereum');
// → FlushTrace sent automatically
// Close the trace when done
await trace.close('Transaction completed successfully');
} catch (error) {
trace.error('transaction_failed', { error: error.message });
await trace.close('Transaction failed');
}
}Tracing Transaction Input Data with ethers.js
When a transaction fails on-chain, the input data (calldata) is still available and contains the encoded function call and parameters. Recording it with addTxInputData() lets you decode and debug the failure later in the Mirador dashboard.
import { Client } from '@miradorlabs/web-sdk';
import { BrowserProvider, parseEther } from 'ethers';
const client = new Client('your-api-key');
async function sendTracedTransaction() {
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const trace = client.trace({ name: 'TokenTransfer' })
.addAttribute('from', signer.address)
.addTags(['transfer', 'ethereum']);
try {
const tx = await signer.sendTransaction({
to: '0xRecipientAddress...',
value: parseEther('0.1'),
data: '0xa9059cbb000000000000000000000000...', // encoded ERC-20 transfer
});
trace.info('transaction_sent', { txHash: tx.hash })
.web3.evm.addTxHint(tx.hash, 'ethereum')
.web3.evm.addInputData(tx.data); // record the calldata for debugging
const receipt = await tx.wait();
trace.info('transaction_confirmed', { blockNumber: receipt.blockNumber });
await trace.close('Transfer completed');
} catch (error) {
// Even on failure, tx.data may be available from the error or the sent tx
trace.error('transaction_failed', { error: error.message });
await trace.close('Transfer failed');
}
}Cross-SDK Trace Sharing
You can share a trace ID between the web SDK and the Node.js SDK to create a unified trace that spans both frontend and backend. This is useful when a user action in the browser triggers server-side processing that should be correlated under the same trace.
Frontend → Backend
Pass the trace ID from the browser to your backend via an HTTP header. Trace IDs are available immediately since they're generated at client.trace() time:
import { Client } from '@miradorlabs/web-sdk';
const client = new Client('your-api-key');
const trace = client.trace({ name: 'Checkout' })
.addAttribute('user', '0xabc...')
.info('checkout_started');
// Trace ID is available immediately — no need to wait for flush
const traceId = trace.getTraceId();
// Pass trace ID to your backend
const response = await fetch('/api/process-order', {
headers: { 'x-mirador-trace-id': traceId },
});On the backend (Node.js SDK):
import { Client } from '@miradorlabs/nodejs-sdk';
const client = new Client('your-api-key');
app.post('/api/process-order', async (req, res) => {
const traceId = req.headers['x-mirador-trace-id'];
// Resume the trace — FlushTrace is idempotent, so this adds to the existing trace
const trace = client.trace({ name: 'ProcessOrder', traceId })
.addAttribute('step', 'backend')
.info('order_processing');
// → auto-flushed via FlushTrace
// ...
await trace.close('Order processed');
});Backend → Frontend
Pass a trace ID from your backend to the browser and resume it:
// Backend creates the trace and returns the ID
const traceId = await getTraceIdFromBackend();
// Resume trace by passing traceId at creation time
const trace = client.trace({ name: 'Dashboard', traceId });MiradorProvider
MiradorProvider is an EIP-1193 provider wrapper that automatically captures transaction data for Mirador traces. Wrap any existing provider to get automatic tracing for eth_sendTransaction and eth_sendRawTransaction calls.
import { Client, MiradorProvider } from '@miradorlabs/web-sdk';
const client = new Client('your-api-key');
// Option 1: Auto-create a new trace per transaction
const provider = new MiradorProvider(window.ethereum, client);
// Option 2: Bind to an existing trace
const trace = client.trace({ name: 'Swap' });
const provider = new MiradorProvider(window.ethereum, client, { trace });
// Option 3: Configure trace options for auto-created traces
const provider = new MiradorProvider(window.ethereum, client, {
traceOptions: { name: 'WalletTx' }
});
// Use like any EIP-1193 provider — transactions are automatically traced
const txHash = await provider.request({
method: 'eth_sendTransaction',
params: [{ from: '0xabc...', to: '0xdef...', value: '0x0' }],
});For each intercepted transaction, MiradorProvider:
- Sets the underlying provider on the trace for chain detection
- Captures
tx:sentevent with transaction hash on success - Captures
tx:errorevent with error details on failure - Adds transaction hash hint and input data automatically
Chain Utilities
Chain Enum
Supported EVM chains, keyed by chain ID:
import { Chain } from '@miradorlabs/web-sdk';
Chain.Ethereum // 1
Chain.Polygon // 137
Chain.Arbitrum // 42161
Chain.Base // 8453
Chain.Optimism // 10
Chain.BSC // 56All chain parameters accept ChainInput — either a Chain enum value or a chain name string ('ethereum', 'polygon', etc.).
toChain(chainId)
Convert a raw chain ID to a Chain enum value.
import { toChain, Chain } from '@miradorlabs/web-sdk';
toChain(1); // Chain.Ethereum
toChain(137); // Chain.Polygon
toChain(42161); // Chain.Arbitrum
toChain('0x1'); // Chain.Ethereum (hex string)
toChain(999); // undefinedAutomatic Client Metadata Collection
When includeUserMeta: true is set (default), the SDK automatically collects:
| Metadata | Description |
|----------|-------------|
| client.browser | Chrome, Firefox, Safari, Edge |
| client.browserVersion | Browser version number |
| client.os | Windows, macOS, Linux, Android, iOS |
| client.osVersion | Operating system version |
| client.deviceType | desktop, mobile, or tablet |
| client.userAgent | Full user agent string |
| client.language | Primary browser language |
| client.languages | All preferred languages (comma-separated) |
| client.screenWidth / client.screenHeight | Screen dimensions |
| client.viewportWidth / client.viewportHeight | Viewport dimensions |
| client.colorDepth | Screen color depth |
| client.pixelRatio | Device pixel ratio (for retina displays) |
| client.cpuCores | Number of CPU cores |
| client.deviceMemory | Device memory in GB (if available) |
| client.touchSupport | Whether touch is supported |
| client.connectionType | Network connection type (4g, 3g, wifi, etc.) |
| client.cookiesEnabled | Whether cookies are enabled |
| client.online | Whether browser is online |
| client.doNotTrack | Do Not Track preference |
| client.timezone | User's timezone |
| client.timezoneOffset | Timezone offset from UTC |
| client.url | Current page URL |
| client.origin | Page origin |
| client.pathname | Page pathname |
| client.referrer | Page referrer |
| client.documentVisibility | Document visibility state |
Note: IP address is captured by the backend from request headers.
Metadata Utilities
The SDK exports the metadata collection functions for advanced usage:
import {
getClientMetadata,
detectBrowser,
detectOS,
detectDeviceType,
} from '@miradorlabs/web-sdk';
const metadata = getClientMetadata(); // Full ClientMetadata object
const browser = detectBrowser(); // e.g., { name: 'Chrome', version: '120.0' }
const os = detectOS(); // e.g., { name: 'macOS', version: '14.0' }
const device = detectDeviceType(); // 'desktop' | 'mobile' | 'tablet'Stack Trace Utilities
The SDK exports utilities for capturing and formatting stack traces:
import {
captureStackTrace,
formatStackTrace,
formatStackTraceReadable
} from '@miradorlabs/web-sdk';
// Capture current stack trace
const stack = captureStackTrace();
// stack.frames: Array of { functionName, fileName, lineNumber, columnNumber }
// stack.raw: Original Error.stack string
// Format for storage (JSON string)
const json = formatStackTrace(stack);
// Format for display (human-readable)
const readable = formatStackTraceReadable(stack);
// Output:
// at myFunction (/path/to/file.js:42:10)
// at caller (/path/to/other.js:15:5)TypeScript Support
Full TypeScript support with exported types:
import {
// Classes
Client,
Trace,
NoopTrace,
MiradorProvider,
// Utilities
captureStackTrace,
formatStackTrace,
formatStackTraceReadable,
toChain,
Chain,
getClientMetadata,
detectBrowser,
detectOS,
detectDeviceType,
// Types
ClientOptions,
TraceOptions, // { name?, traceId?, includeUserMeta?, autoClose?, provider?, autoKeepAlive?, maxTraceLifetimeMs?, maxQueueSize?, callbacks?, ... }
Severity, // Info, Warn, Error
AddEventOptions, // { captureStackTrace?: boolean, severity?: Severity } (for addEvent)
StackFrame, // { functionName, fileName, lineNumber, columnNumber }
StackTrace, // { frames: StackFrame[], raw: string }
ChainName, // 'ethereum' | 'polygon' | 'arbitrum' | 'base' | 'optimism' | 'bsc'
ChainInput, // Chain | ChainName
TraceEvent, // { eventName, details?, timestamp }
TxHashHint, // { txHash, chain, details?, timestamp }
SafeTxHintData, // { safeTxHash, chain, details?, timestamp }
SafeMsgHintData, // { messageHash, chain, details?, timestamp }
ClientMetadata, // Browser/OS metadata fields
EIP1193Provider, // { request(args): Promise<unknown> }
TxHintOptions, // { input?, details? }
TransactionLike, // { hash, data?, input?, chainId? }
TransactionRequest, // { from, to?, data?, value?, ... }
MiradorProviderOptions, // { trace?, traceOptions? }
Logger, // { debug(), warn(), error() }
TraceCallbacks, // { onFlushed?, onFlushError?, onClosed?, onDropped? }
} from '@miradorlabs/web-sdk';Browser Compatibility
This SDK uses modern browser APIs and is compatible with:
- ES2020+
- Fetch API
- Promises
- Modern browsers (Chrome, Firefox, Safari, Edge)
For older browsers, you may need polyfills.
Module Formats
The package provides multiple module formats:
- ESM (
dist/index.esm.js): For modern bundlers (Webpack, Vite, Rollup) - UMD (
dist/index.umd.js): For browser globals and older module systems - TypeScript (
dist/index.d.ts): Type definitions
Development
Building
npm run buildTesting
npm test
npm run test:watch
npm run test:coveragePublishing
npm run release:patch # 1.0.x
npm run release:minor # 1.x.0
npm run release:major # x.0.0Example Application
A complete working example is available in the example/ directory. It demonstrates:
- Wallet connection using EIP-6963 (Multi Injected Provider Discovery)
- Creating and managing traces
- Adding attributes, tags, and events
- Blockchain transaction correlation with
web3.evm.addTxHint() - Safe multisig tracking with
web3.safe.addMsgHint()andweb3.safe.addTxHint() - Network switching and balance display
To run the example:
cd example
npm install
npm run build
npm startThen open http://localhost:8000 in your browser.
License
MIT
Author
@miradorlabs
