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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@lmes/duckling

v0.0.4

Published

High-performance WebSocket SDK for Duckling DuckDB Server

Readme

DuckDB WebSocket SDK

High-performance TypeScript SDK for connecting to DuckDB server via WebSocket. Designed for low-latency, high-throughput query execution with automatic reconnection and connection pooling support.

Features

  • Auto-Connect: Automatically connects on first query (no manual connect() needed)
  • Auto-Ping: Keeps connection alive with automatic health checks every 30s
  • WebSocket Connection: Persistent connection with 5-15ms latency (vs 50-100ms for HTTP)
  • API Key Authentication: Secure authentication using DUCKLING_API_KEY
  • Auto-Reconnection: Automatic reconnection with exponential backoff
  • Connection Pooling: Built-in support for connection pools
  • Parallel Queries: Execute multiple queries concurrently
  • Type-Safe: Full TypeScript support with type inference
  • High Throughput: 10,000+ queries/second capability
  • Error Handling: Comprehensive error handling and timeout management

Installation

cd sdk
pnpm install
pnpm run build

Quick Start

import { DucklingClient } from '@lmes/duckling';

// Initialize client - auto-connect and auto-ping enabled by default
const client = new DucklingClient({
  url: 'ws://localhost:3001/ws',
  apiKey: process.env.DUCKLING_API_KEY
});

// Just query - client auto-connects on first query!
const users = await client.query('SELECT * FROM User LIMIT 10');

// Auto-ping keeps connection alive
// Close when done
client.close();

TypeScript Support

The SDK provides comprehensive TypeScript types for full type safety and IntelliSense support.

Typed Query Results

// Define your schema
interface User {
  id: number;
  name: string;
  email: string;
  createdAt: string;
}

// Get fully-typed results
const users = await client.query<User>('SELECT * FROM User LIMIT 10');
// users is typed as User[]
// Full IntelliSense for users[0].email, users[0].name, etc.

Available Types

import {
  DucklingClient,

  // Core types
  QueryMessage,
  QueryResponse,

  // Config types
  DuckDBSDKConfig,
  ConnectionStats,

  // Query result types
  CountResult,
  AggregateResult,
  QueryRow,

  // Pagination types
  PaginationOptions,
  PaginatedResult,

  // Batch query types
  BatchQueryRequest,
  BatchQueryResult,

  // Event types
  DucklingClientEvents,

  // Error types
  DuckDBError,
  DuckDBErrorType
} from '@lmes/duckling';

For complete type documentation, see TYPES.md.

Configuration

interface DuckDBSDKConfig {
  url: string;                    // WebSocket server URL
  apiKey: string;                 // API key for authentication
  autoConnect?: boolean;          // Auto-connect on first query (default: true)
  autoPing?: boolean;             // Auto-ping to keep alive (default: true)
  pingInterval?: number;          // Ping interval in ms (default: 30000)
  autoReconnect?: boolean;        // Auto-reconnect on failure (default: true)
  maxReconnectAttempts?: number;  // Max reconnection attempts (default: 5)
  reconnectDelay?: number;        // Reconnect delay in ms (default: 1000)
  connectionTimeout?: number;     // Connection timeout in ms (default: 5000)
}

API Reference

DucklingClient

connect(): Promise<void>

Connect to DuckDB server and authenticate with API key.

await client.connect();

query<T>(sql: string, params?: any[]): Promise<T[]>

Execute SQL query and return results.

const users = await client.query<User>('SELECT * FROM User WHERE id = ?', [123]);

queryBatch<T>(queries: string[]): Promise<T[][]>

Execute multiple queries in parallel.

const results = await client.queryBatch([
  'SELECT COUNT(*) FROM User',
  'SELECT COUNT(*) FROM Product'
]);

queryPaginated<T>(sql: string, options: PaginationOptions): Promise<PaginatedResult<T>>

Execute paginated query with automatic LIMIT and OFFSET.

const result = await client.queryPaginated<User>(
  'SELECT * FROM User ORDER BY createdAt DESC',
  { limit: 20, offset: 0 }
);

console.log(`Showing ${result.data.length} users`);
console.log(`Has more: ${result.pagination.hasMore}`);

queryBatchDetailed<T>(requests: BatchQueryRequest[]): Promise<BatchQueryResult<T>[]>

Execute batch queries with individual success/failure handling.

const requests: BatchQueryRequest[] = [
  { sql: 'SELECT * FROM User LIMIT 10' },
  { sql: 'SELECT * FROM Order LIMIT 10' }
];

const results = await client.queryBatchDetailed(requests);

results.forEach((result) => {
  if (result.success) {
    console.log(`Success: ${result.data?.length} rows in ${result.duration}ms`);
  } else {
    console.error(`Failed: ${result.error}`);
  }
});

ping(): Promise<boolean>

Test connection with ping.

const isAlive = await client.ping();

close(): void

Close WebSocket connection.

client.close();

isConnected(): boolean

Check if client is connected and authenticated.

if (client.isConnected()) {
  // Execute queries
}

getStats()

Get connection statistics.

const stats = client.getStats();
console.log(stats);
// {
//   connected: true,
//   authenticated: true,
//   pendingRequests: 2,
//   reconnectAttempts: 0,
//   url: 'ws://localhost:3001/ws'
// }

Examples

Basic Query

pnpm run example:basic

Simple query execution with auto-connect:

import { DucklingClient } from '@lmes/duckling';

const client = new DucklingClient({
  url: 'ws://localhost:3001/ws',
  apiKey: process.env.DUCKLING_API_KEY
  // autoConnect: true (default)
  // autoPing: true (default - keeps connection alive)
});

// Just query - auto-connects on first use!
const users = await client.query('SELECT * FROM User LIMIT 5');
console.table(users);
client.close();

Parallel Queries

pnpm run example:parallel

Execute multiple queries concurrently for maximum throughput:

const queries = [
  'SELECT COUNT(*) FROM User',
  'SELECT COUNT(*) FROM Product',
  'SELECT COUNT(*) FROM ActivityLog'
];

const results = await client.queryBatch(queries);
// 3-5x faster than sequential execution

Connection Pool

pnpm run example:connection-pool

High-concurrency scenarios with connection pooling:

const pool = new DuckDBConnectionPool(5, {
  url: 'ws://localhost:3001/ws',
  apiKey: process.env.DUCKLING_API_KEY
});

await pool.initialize();
const results = await pool.queryBatch(queries);
pool.close();

Performance

Latency Comparison

| Method | Average Latency | Use Case | |--------|----------------|----------| | HTTP API | 50-100ms | Standard queries | | WebSocket (this SDK) | 5-15ms | Real-time dashboards |

Throughput

  • Sequential: ~20-50 queries/second
  • Parallel (single connection): ~500-1,000 queries/second
  • Connection Pool (5 connections): ~2,000-5,000 queries/second
  • Maximum Capacity: 10,000+ queries/second

Error Handling

The SDK emits events for connection lifecycle:

client.on('connected', () => {
  console.log('Connected to DuckDB server');
});

client.on('disconnected', () => {
  console.log('Disconnected from server');
});

client.on('error', (error) => {
  console.error('WebSocket error:', error);
});

Handle query errors with try-catch:

try {
  const result = await client.query('SELECT * FROM NonExistentTable');
} catch (error) {
  console.error('Query failed:', error.message);
}

Auto-Connect & Auto-Ping

The SDK automatically connects on first query and keeps the connection alive:

import { DucklingClient } from '@lmes/duckling';

const client = new DucklingClient({
  url: 'ws://localhost:3001/ws',
  apiKey: process.env.DUCKLING_API_KEY
  // autoConnect: true (default)
  // autoPing: true (default)
  // pingInterval: 30000 (default - ping every 30s)
});

// No need to call connect() - auto-connects on first query!
const result = await client.query('SELECT * FROM User');

// Auto-ping keeps connection alive automatically
// Perfect for long-running connections

Auto-Reconnection

The SDK automatically reconnects on connection failure:

const client = new DucklingClient({
  url: 'ws://localhost:3001/ws',
  apiKey: 'your-api-key',
  autoReconnect: true,          // default: true
  maxReconnectAttempts: 5,      // default: 5
  reconnectDelay: 1000          // default: 1000ms, exponential backoff
});

// Connection will auto-reconnect up to 5 times on failure
// Delays: 1s, 2s, 3s, 4s, 5s

Environment Variables

# .env
DUCKLING_API_KEY=your-api-key-here
DUCKLING_WS_URL=ws://localhost:3001/ws  # Optional

Architecture

Dashboard → SDK → WebSocket → DuckDB Server
            ↓
     [Connection Pool]
     [Auto-Reconnect]
     [Query Queuing]

Use Cases

Real-Time Dashboards

// Update dashboard every second with fresh data
setInterval(async () => {
  const stats = await client.query('SELECT * FROM dashboard_stats');
  updateUI(stats);
}, 1000);

Batch Processing

// Process 1000 queries efficiently
const queries = generateQueries(1000);
const batchSize = 50;

for (let i = 0; i < queries.length; i += batchSize) {
  const batch = queries.slice(i, i + batchSize);
  const results = await client.queryBatch(batch);
  processBatch(results);
}

Microservices Integration

// API endpoint handler
app.get('/api/users/:id', async (req, res) => {
  const user = await client.query(
    'SELECT * FROM User WHERE id = ?',
    [req.params.id]
  );
  res.json(user[0]);
});

Requirements

  • Node.js 18+
  • TypeScript 5.0+
  • DuckDB Server with WebSocket support
  • Valid DUCKLING_API_KEY

License

MIT