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

kalam-link

v0.2.0-alpha1

Published

WebAssembly-compatible KalamDB client library with TypeScript support

Readme

kalam-link

Official TypeScript/JavaScript client for KalamDB.

  • Execute SQL over HTTP
  • Subscribe to real-time changes over WebSocket
  • Works in modern browsers and Node.js (>= 18)

Installation

npm i kalam-link

Quick Start

import { createClient, Auth, MessageType, ChangeType } from 'kalam-link';

const client = createClient({
  url: 'http://localhost:8080',
  auth: Auth.basic('admin', 'admin'),
});

await client.connect();

// Query
const result = await client.query('SELECT 1 AS ok');
console.log(result.results[0]);

// Subscribe (returns an unsubscribe function)
const unsubscribe = await client.subscribe('app.messages', (event) => {
  switch (event.type) {
    case MessageType.Change:
      if (event.change_type === ChangeType.Insert) {
        console.log('New row:', event.rows);
      }
      break;
    case MessageType.InitialDataBatch:
      console.log('Initial data:', event.rows);
      break;
    case MessageType.Error:
      console.error('Subscription error:', event.message);
      break;
  }
});

// Later
await unsubscribe();
await client.disconnect();

Authentication

import { createClient, Auth } from 'kalam-link';

// Username/password
createClient({ url: 'http://localhost:8080', auth: Auth.basic('user', 'pass') });

// JWT token
createClient({ url: 'http://localhost:8080', auth: Auth.jwt('eyJhbGciOiJIUzI1NiIs...') });

// No auth (for local/dev setups that allow it)
createClient({ url: 'http://localhost:8080', auth: Auth.none() });

API Reference (Complete)

Everything below is exported from kalam-link unless noted otherwise.

Imports

import KalamDBClient, {
  createClient,
  Auth,
  // Enums
  MessageType,
  ChangeType,
  BatchStatus,
  // Types
  type AuthCredentials,
  type BasicAuthCredentials,
  type JwtAuthCredentials,
  type NoAuthCredentials,
  type ClientOptions,
  type ClientOptionsWithAuth,
  type ClientOptionsLegacy,
  type ConnectionOptions,
  type SubscriptionOptions,
  type SubscribeOptions,
  type QueryResponse,
  type QueryResult,
  type SchemaField,
  type ErrorDetail,
  type ServerMessage,
  type BatchControl,
  type SubscriptionCallback,
  type SubscriptionInfo,
  type Unsubscribe,
  type WasmKalamClient,
  // Helpers
  buildAuthHeader,
  encodeBasicAuth,
  isAuthenticated,
  isBasicAuth,
  isJwtAuth,
  isNoAuth,
} from 'kalam-link';

Factory

createClient(options: ClientOptions): KalamDBClient

type ClientOptions = ClientOptionsWithAuth | ClientOptionsLegacy;

interface ClientOptionsWithAuth {
  url: string;
  auth: AuthCredentials;
}

interface ClientOptionsLegacy {
  url: string;
  username: string;
  password: string;
}

Class: KalamDBClient (default export)

Constructors

new KalamDBClient(options: ClientOptionsWithAuth)

// Legacy (deprecated)
new KalamDBClient(url: string, username: string, password: string)

Lifecycle

initialize(): Promise<void>
connect(): Promise<void>
disconnect(): Promise<void>
isConnected(): boolean

Authentication

getAuthType(): 'basic' | 'jwt' | 'none'

Queries

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

Convenience DML

insert(tableName: string, data: Record<string, any>): Promise<QueryResponse>
delete(tableName: string, rowId: string | number): Promise<void>

Subscriptions

subscribe(
  tableName: string,
  callback: SubscriptionCallback,
  options?: SubscriptionOptions
): Promise<Unsubscribe>

subscribeWithSql(
  sql: string,
  callback: SubscriptionCallback,
  options?: SubscriptionOptions
): Promise<Unsubscribe>

unsubscribe(subscriptionId: string): Promise<void>
unsubscribeAll(): Promise<void>

Subscription helpers:

getSubscriptionCount(): number
getSubscriptions(): SubscriptionInfo[]
isSubscribedTo(tableNameOrSql: string): boolean
getLastSeqId(subscriptionId: string): string | undefined

Reconnection controls

setAutoReconnect(enabled: boolean): void
setReconnectDelay(initialDelayMs: number, maxDelayMs: number): void
setMaxReconnectAttempts(maxAttempts: number): void
getReconnectAttempts(): number
isReconnecting(): boolean

Auth API

Types

interface BasicAuthCredentials { type: 'basic'; username: string; password: string }
interface JwtAuthCredentials { type: 'jwt'; token: string }
interface NoAuthCredentials { type: 'none' }

type AuthCredentials =
  | BasicAuthCredentials
  | JwtAuthCredentials
  | NoAuthCredentials;

Factories

Auth.basic(username: string, password: string): BasicAuthCredentials
Auth.jwt(token: string): JwtAuthCredentials
Auth.none(): NoAuthCredentials

Helpers

encodeBasicAuth(username: string, password: string): string
buildAuthHeader(auth: AuthCredentials): string | undefined

isBasicAuth(auth: AuthCredentials): auth is BasicAuthCredentials
isJwtAuth(auth: AuthCredentials): auth is JwtAuthCredentials
isNoAuth(auth: AuthCredentials): auth is NoAuthCredentials
isAuthenticated(auth: AuthCredentials): auth is BasicAuthCredentials | JwtAuthCredentials

Query result types

interface SchemaField {
  name: string;
  data_type: string;
  index: number;
}

interface QueryResult {
  schema: SchemaField[];
  rows?: unknown[][];
  row_count: number;
  message?: string;
}

interface QueryResponse {
  status: 'success' | 'error';
  results: QueryResult[];
  took?: number;
  error?: ErrorDetail;
}

interface ErrorDetail {
  code: string;
  message: string;
  details?: any;
}

Enums

// Message type for WebSocket subscription events
enum MessageType {
  SubscriptionAck = 'subscription_ack',
  InitialDataBatch = 'initial_data_batch',
  Change = 'change',
  Error = 'error',
}

// Change type for live subscription change events
enum ChangeType {
  Insert = 'insert',
  Update = 'update',
  Delete = 'delete',
}

// Batch loading status
enum BatchStatus {
  Loading = 'loading',
  LoadingBatch = 'loading_batch',
  Ready = 'ready',
}

Live subscription event types

type ServerMessage =
  | {
      type: MessageType.SubscriptionAck;
      subscription_id: string;
      total_rows: number;
      batch_control: BatchControl;
      schema: SchemaField[];
    }
  | {
      type: MessageType.InitialDataBatch;
      subscription_id: string;
      rows: Record<string, any>[];
      batch_control: BatchControl;
    }
  | {
      type: MessageType.Change;
      subscription_id: string;
      change_type: ChangeType;
      rows?: Record<string, any>[];
      old_values?: Record<string, any>[];
    }
  | {
      type: MessageType.Error;
      subscription_id: string;
      code: string;
      message: string;
    };

interface BatchControl {
  batch_num: number;
  has_more: boolean;
  status: BatchStatus;
  last_seq_id?: string;
  snapshot_end_seq?: string;
}

type SubscriptionCallback = (event: ServerMessage) => void;
type Unsubscribe = () => Promise<void>;

interface SubscriptionInfo {
  id: string;
  tableName: string;
  createdAt: Date;
}

Options

interface ConnectionOptions {
  auto_reconnect?: boolean;
  reconnect_delay_ms?: number;
  max_reconnect_delay_ms?: number;
  max_reconnect_attempts?: number;
}

interface SubscriptionOptions {
  batch_size?: number;
  last_rows?: number;
  from_seq_id?: string;
}

type SubscribeOptions = SubscriptionOptions;

Advanced: WASM entrypoint (kalam-link/wasm)

import init, {
  KalamClient,
  WasmTimestampFormatter,
  parseIso8601,
  timestampNow,
  initSync,
} from 'kalam-link/wasm';

Exports:

  • default init(moduleOrPath?) => Promise<InitOutput>
  • initSync(moduleOrBytes) => InitOutput
  • class KalamClient (low-level WASM client)
  • class WasmTimestampFormatter
  • parseIso8601(isoString: string): number
  • timestampNow(): number

Notes (Browser/Node)

This package includes a small .wasm runtime under the hood.

  • In browsers with bundlers (Vite/Webpack/Rollup), it should “just work”.
  • If you see WASM loading errors, ensure your build serves/copies: node_modules/kalam-link/dist/wasm/kalam_link_bg.wasm

Links

  • KalamDB repository: https://github.com/jamals86/KalamDB
  • Issues: https://github.com/jamals86/KalamDB/issues

Development (Build From This Repo)

Only needed if you are contributing to the SDK.

Prerequisites:

  • Node.js >=18
  • Rust toolchain + wasm-pack
cd link/sdks/typescript
npm install
npm run build

License

Apache-2.0 (see the repository root).

Contributing

Issues/PRs are welcome: https://github.com/jamals86/KalamDB/issues