kalam-client
Official Rust SDK for KalamDB — SQL, materialized live rows, and strong tenant isolation in one crate.
KalamDB is built for apps where every user or tenant owns a private data space. The same SQL can run for every signed-in customer, while USER tables ensure each query only touches that caller's data. On the server and in native SDKs, the default realtime API is live(): you receive the current materialized row set, not a stream of low-level diff frames that your UI has to reconcile.
→ kalamdb.org · Docs · GitHub
kalam-client provides:
- SQL execution over HTTP
- materialized live query rows over WebSocket with
live()andlive_with_config() - low-level realtime events with
live_events()when you need raw frames - per-user and per-tenant isolation with USER tables
- optional topic consumer workers behind the
consumerfeature - optional multipart file upload helpers behind the
file-uploadsfeature
Runtime targets:
- Tokio-based async Rust (
native-sdk, enabled by default)
Browser WebAssembly builds for @kalamdb/client live in the separate
kalam-link-wasm crate (not part of this published SDK).
Installation
Add the crate from crates.io (or a path dependency while developing inside this repository):
[]
= "0.5"
= { = "1", = ["macros", "rt-multi-thread"] }
Enable optional capabilities with Cargo features:
# App-facing SQL + live rows (default)
= { = "0.5", = ["native-sdk"] }
# Topic workers and batch consumption
= { = "0.5", = ["native-sdk", "consumer"] }
# Multipart SQL file uploads
= { = "0.5", = ["native-sdk", "file-uploads"] }
| Feature | Description |
|---|---|
native-sdk (default) |
Tokio runtime, HTTP queries, auth flows, live subscriptions |
consumer |
TopicConsumer, ConsumerBuilder, consume/ack topic APIs |
file-uploads |
Multipart SQL upload helpers |
healthcheck |
Cached /v1/api/healthcheck helper |
setup |
First-run server setup helpers |
cluster |
Cluster health inspection |
Topic workers ship in the same crate behind consumer so app-only installs stay lean, matching how @kalamdb/consumer extends @kalamdb/client in TypeScript.
Why live() First
Most UIs do not want subscription_ack, initial_data_batch, change, and error frames. They want the latest rows.
live() gives you exactly that:
- the current row set already reconciled for insert, update, and delete
- one event shape for initial load and future changes
- shared behavior with the TypeScript and Dart clients
- simpler services, CLIs, and background workers
Use SubscriptionOptions::with_last_rows() when you want an initial rewind from the server. Use LiveRowsConfig { limit: Some(n), .. } when you want the client to keep the materialized live row set bounded over time.
The knobs apply at different layers:
batch_sizechunks the initial snapshot from the serverlast_rowschooses how much history to rewind firstlimitcaps the materialized live row set the client keeps afterward
Use live_events() only when you need the raw event protocol.
Quick Start
Start with a USER table. The SQL stays simple, and KalamDB scopes the data per authenticated user.
CREATE NAMESPACE IF NOT EXISTS support;
(
id BIGINT PRIMARY KEY DEFAULT SNOWFLAKE_ID,
room TEXT NOT NULL DEFAULT 'main',
role TEXT NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW
) WITH (TYPE = 'USER');
use Duration;
use ;
use json;
async
See QUICKSTART.md for a shorter copy-paste flow and examples for runnable projects.
Resume From a Specific SeqId
When you want offline resume or a durable checkpoint, persist the last SeqId you applied and feed it back through SubscriptionOptions::with_from().
use ;
let start_from = from;
let options = new
.with_last_rows
.with_from;
Each LiveRowsEvent::Rows includes last_seq_id so you can persist checkpoints between sessions.
Lower-Level Realtime API
If you need raw protocol frames, use live_events().
use ;
let config =
new;
let mut events = client.live_events_with_config.await?;
while let Some = events.next.await
Use this API for protocol tooling, debugging, or custom reconciliation. For app UI state, prefer live().
Topics and Workers
Topic workers live behind the optional consumer feature so app-only installs keep the main SDK lean.
[]
= { = "0.5", = ["native-sdk", "consumer"] }
Use the default client surface for app-facing SQL, live rows, subscriptions, auth, and files. Enable consumer for TopicConsumer, ConsumerBuilder, consume_batch(), and ack().
use AutoOffsetReset;
let consumer = client
.consumer
.group_id
.topic
.auto_offset_reset
.build?;
See examples/topic-consumer for a fuller worker loop.
Files
KalamDB tables can include FILE columns. Upload with multipart SQL, read metadata from query results, and download bytes through the same client.
Enable uploads with the file-uploads feature (included in native-cli / e2e-tests):
= { = "0.5", = ["native-sdk", "file-uploads"] }
use ;
let files = vec!;
client.execute_with_files.await?;
let rows = client
.execute_query
.await?;
let table_id = from_strings;
let file_ref = rows.results.rows
.as_bound_file
.expect;
let download = client.download_bound_file.await?;
write?;
Key types:
FileRef— table-agnostic file metadata plusstored_name()TableId— type-safe namespace/table identity fromkalamdb-commonsBoundFileRef—FileRefplus table context for downloadsFileUpload— multipart upload payload forFILE("placeholder")SQLQueryParam— type-safe SQL parameters (Text,Int,File, …)KalamCellValue::as_file()— parse FILE cells from query/live rowsKalamCellValue::as_bound_file(&TableId)— parse and attach table contextFileDownload— bytes plus response headers fromdownload_bound_file()/download_file()
Authentication
AuthProvider is the canonical way to configure the client.
use AuthProvider;
// Static JWT
let auth = jwt_token;
// Basic auth (exchanged for JWT on first use)
let auth = basic_auth;
// Local root / system user
let auth = system_user_auth;
The SDK handles:
- Basic-auth-to-JWT exchange
- default namespace forwarding for
/v1/api/sqlplus unqualified live/file contexts - shared WebSocket connection management
- reconnect controls and
SeqIdtracking
Examples and Tests
| Example | What it shows |
|---|---|
| quickstart | Connect, run SELECT CURRENT_USER(), disconnect |
| file-attachments | FILE upload, as_bound_file, download_bound_file |
| live-inbox | USER table + materialized live() loop |
| topic-consumer | consumer feature + TopicConsumer |
tests/*.rs |
Offline API guards plus server-backed integration tests |
Run the SDK test suite from this directory:
NO_SERVER=true
From the repo root:
Set KALAMDB_SERVER_URL (default http://localhost:2900) and credentials as needed.
API Pointers
execute_query()and related SQL helpers for reads and writesQueryParam,FileUpload,FileRef, andFileDownloadfor typed SQL and FILE columnsexecute_with_files()for FILE column uploads (file-uploadsfeature)download_bound_file()for context-bound FILE downloads;download_file()remains available for explicit namespace/table callslive()andlive_with_config()for materialized realtime rowslive_events()andlive_events_with_config()for low-level subscription framesTopicConsumerandclient.consumer()(featureconsumer) for topic consumption and commits
Full docs: kalamdb.org/docs/sdk/rust
Issues: github.com/kalamdb/KalamDB/issues
For crate development, publishing, and contribution details, see DEV.md.
License
Licensed under the Apache License, Version 2.0 (Apache-2.0). See LICENSE.