kalam-link
v0.2.0-alpha1
Published
WebAssembly-compatible KalamDB client library with TypeScript support
Maintainers
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-linkQuick 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(): booleanAuthentication
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 | undefinedReconnection controls
setAutoReconnect(enabled: boolean): void
setReconnectDelay(initialDelayMs: number, maxDelayMs: number): void
setMaxReconnectAttempts(maxAttempts: number): void
getReconnectAttempts(): number
isReconnecting(): booleanAuth 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(): NoAuthCredentialsHelpers
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 | JwtAuthCredentialsQuery 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) => InitOutputclass KalamClient(low-level WASM client)class WasmTimestampFormatterparseIso8601(isoString: string): numbertimestampNow(): 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 buildLicense
Apache-2.0 (see the repository root).
Contributing
Issues/PRs are welcome: https://github.com/jamals86/KalamDB/issues
