npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@luziadev/sdk

v1.0.0

Published

Official TypeScript SDK for the Luzia cryptocurrency pricing API

Readme

@luziadev/sdk

Official TypeScript SDK for the Luzia cryptocurrency pricing API.

Installation

bun add @luziadev/sdk
# or
npm install @luziadev/sdk

Quick Start

import { Luzia } from '@luziadev/sdk'

const luzia = new Luzia({
  apiKey: 'lz_your_api_key',
})

// List all supported exchanges
const exchanges = await luzia.exchanges.list()
console.log(exchanges)
// [{ id: 'binance', name: 'Binance', status: 'operational', ... }]

// Get a single ticker
const ticker = await luzia.tickers.get('binance', 'BTC/USDT')
console.log(`BTC/USDT: $${ticker.last}`)

// Get all tickers for an exchange
const { tickers, total } = await luzia.tickers.list('binance', { limit: 50 })
console.log(`Found ${total} tickers`)

// Get markets with filters
const { markets } = await luzia.markets.list('binance', { quote: 'USDT' })

Configuration

const luzia = new Luzia({
  // Required: Your API key
  apiKey: 'lz_xxxxx',

  // Optional: Custom base URL (default: https://api.luzia.dev)
  baseUrl: 'http://localhost:3000',

  // Optional: Request timeout in ms (default: 30000)
  timeout: 10000,

  // Optional: Retry configuration
  retry: {
    maxRetries: 3,        // Number of retry attempts (default: 3)
    initialDelayMs: 1000, // Initial delay before first retry (default: 1000)
    maxDelayMs: 30000,    // Maximum delay between retries (default: 30000)
    backoffMultiplier: 2, // Multiplier for exponential backoff (default: 2)
    jitter: true,         // Add random jitter to delays (default: true)
  },
})

API Reference

Exchanges

// List all supported exchanges
const exchanges = await luzia.exchanges.list()

Tickers

// Get a single ticker
const ticker = await luzia.tickers.get('binance', 'BTC/USDT')

// List all tickers for an exchange
const { tickers, total, limit, offset } = await luzia.tickers.list('binance', {
  limit: 50,
  offset: 0,
})

// Get specific tickers across exchanges
const { tickers } = await luzia.tickers.listFiltered({
  exchange: 'binance',           // Optional: filter by exchange
  symbols: ['BTC/USDT', 'ETH/USDT'], // Optional: filter by symbols
  limit: 100,
  offset: 0,
})

Markets

// List markets for an exchange
const { markets, total } = await luzia.markets.list('binance', {
  base: 'BTC',    // Optional: filter by base currency
  quote: 'USDT',  // Optional: filter by quote currency
  active: true,   // Optional: filter by active status
  limit: 100,
  offset: 0,
})

WebSocket (Real-Time Updates)

Stream live ticker updates over WebSocket. Requires a Pro plan or higher.

Quick Start

import { Luzia } from '@luziadev/sdk'

const luzia = new Luzia({ apiKey: 'lz_your_api_key' })
const ws = luzia.createWebSocket()

ws.on('connected', (info) => {
  console.log(`Connected (${info.tier}), max subscriptions: ${info.limits.maxSubscriptions}`)
  ws.subscribe(['ticker:binance:BTC/USDT', 'ticker:coinbase:ETH/USDT'])
})

ws.on('ticker', (data) => {
  console.log(`${data.exchange} ${data.symbol}: $${data.data.last}`)
})

ws.on('error', (err) => {
  console.error(`WebSocket error [${err.code}]: ${err.message}`)
})

ws.connect()

Channel Format

  • ticker:{exchange}:{symbol} — specific pair (e.g., ticker:binance:BTC/USDT)
  • ticker:{exchange} — all tickers from an exchange (e.g., ticker:binance)

Subscribing and Unsubscribing

// Subscribe to channels (can be called before or after connect)
ws.subscribe(['ticker:binance:BTC/USDT', 'ticker:kraken:ETH/USDT'])

// Unsubscribe from channels
ws.unsubscribe(['ticker:binance:BTC/USDT'])

// Check active subscriptions
console.log(ws.subscriptions) // ReadonlySet<string>

Connection Options

const ws = luzia.createWebSocket({
  autoReconnect: true,        // Auto-reconnect on disconnection (default: true)
  maxReconnectAttempts: 10,   // Max attempts, 0 = infinite (default: 10)
  reconnectDelayMs: 1000,     // Initial reconnect delay (default: 1000ms)
  maxReconnectDelayMs: 30000, // Max reconnect delay (default: 30000ms)
  heartbeatIntervalMs: 30000, // Heartbeat interval, 0 = disabled (default: 30000ms)
})

Events

| Event | Payload | Description | |-------|---------|-------------| | connected | { tier, limits } | Connection established, server ready | | ticker | { exchange, symbol, data, timestamp } | Price update received | | subscribed | { channel } | Channel subscription confirmed | | unsubscribed | { channel } | Channel unsubscription confirmed | | error | { code, message } | Error from server or connection | | disconnected | { code, reason } | Connection closed | | reconnecting | { attempt, delayMs } | Reconnect attempt starting |

Connection State

console.log(ws.state) // 'disconnected' | 'connecting' | 'connected' | 'reconnecting'

Disconnecting

// Gracefully close and disable auto-reconnect
ws.disconnect()

Connection Limits

| Tier | Connections | Subscriptions / Connection | |------|-------------|----------------------------| | Free | Not available | — | | Pro | 5 | 50 | | Enterprise | 25 | 500 |

Error Handling

The SDK uses a single LuziaError class with a code property to distinguish error types:

import { Luzia, LuziaError } from '@luziadev/sdk'

try {
  const ticker = await luzia.tickers.get('invalid', 'BTC/USDT')
} catch (error) {
  if (error instanceof LuziaError) {
    switch (error.code) {
      case 'auth':
        console.log('Invalid API key')
        break
      case 'rate_limit':
        console.log(`Rate limited. Retry after ${error.retryAfter} seconds`)
        console.log(`Limit info:`, error.rateLimitInfo)
        break
      case 'not_found':
        console.log('Resource not found')
        break
      case 'validation':
        console.log('Invalid request parameters:', error.details)
        break
      case 'server':
        console.log('Server error (exchange may be temporarily unavailable)')
        break
      case 'network':
        console.log('Network error:', error.message)
        break
      case 'timeout':
        console.log(`Request timed out after ${error.timeoutMs}ms`)
        break
    }
  }
}

Checking Error Types

import { isLuziaError, isRetryableError } from '@luziadev/sdk'

if (isLuziaError(error)) {
  console.log(`Luzia error: ${error.message}`)
}

if (isRetryableError(error)) {
  console.log('This error can be retried')
}

Rate Limit Information

Access rate limit information from the most recent request:

const ticker = await luzia.tickers.get('binance', 'BTC/USDT')

const info = luzia.rateLimitInfo
if (info) {
  console.log(`Requests remaining: ${info.remaining}/${info.limit}`)
  console.log(`Resets at: ${new Date(info.reset * 1000)}`)

  // Free tier also has daily limits
  if (info.dailyLimit) {
    console.log(`Daily remaining: ${info.dailyRemaining}/${info.dailyLimit}`)
  }
}

Automatic Retries

The SDK automatically retries requests on:

  • Rate limit errors (429) - respects Retry-After header
  • Timeout errors (408)
  • Server errors (500, 502, 503, 504)
  • Network errors

Non-retryable errors (400, 401, 403, 404) are thrown immediately.

Custom Retry Handling

import { withRetry } from '@luziadev/sdk'

// Use the retry utility directly
const result = await withRetry(
  () => luzia.tickers.get('binance', 'BTC/USDT'),
  { maxRetries: 5 },
  (context) => {
    console.log(`Retry attempt ${context.attempt + 1}/${context.maxRetries}`)
  }
)

Types

All types are exported for use in your application:

import type {
  // REST API
  Exchange,
  ExchangeStatus,
  Market,
  Ticker,
  RateLimitInfo,
  LuziaOptions,
  RetryOptions,
  // WebSocket
  WebSocketOptions,
  WSTickerData,
  WSConnectedData,
  WSErrorData,
  WSEventMap,
  WSConnectionState,
} from '@luziadev/sdk'

Development

# Install dependencies
bun install

# Generate types from OpenAPI spec
bun run generate

# Type check
bun run typecheck

# Run tests
bun test

Links

License

MIT