Setup & Quick Start
Status: This SDK is in beta and may still change between releases.
The Dart/Flutter SDK is kalam_link (pub package name: kalam_link). It is a thin Dart layer over a Rust core bridged via Flutter Rust Bridge. The current package surface covers init, auth, querying, subscriptions, and connection diagnostics. Topic consumer / ACK worker APIs, initial server bootstrap flows, and dedicated health-check helpers stay outside the Dart SDK.
Install
Add to pubspec.yaml:
dependencies:
kalam_link: ^0.4.1-beta.2Then fetch dependencies:
flutter pub get
# or
dart pub getSupported platforms (per plugin configuration): Android, iOS, macOS, Windows, Linux.
If you’re evaluating web builds: check the current package release notes first. Flutter FFI plugins may require additional setup for web/WASM targets. Repository web builds use the
release-distCargo profile plus awasm-opt -Ozpost-pass to keep the shipped WASM artifact small.
Required initialization
You must call KalamClient.init() exactly once at app startup, before any other SDK call.
Flutter:
import 'package:flutter/widgets.dart';
import 'package:kalam_link/kalam_link.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await KalamClient.init();
// runApp(const MyApp());
}Pure Dart (non-Flutter):
import 'package:kalam_link/kalam_link.dart';
Future<void> main() async {
await KalamClient.init();
}Create a client
KalamClient.connect(...) constructs a client handle. Prefer authProvider for expiring tokens.
import 'package:kalam_link/kalam_link.dart';
final client = await KalamClient.connect(
url: 'http://localhost:8080',
authProvider: () async => Auth.jwt(await getJwtFromSecureStorage()),
);If you do not have auth enabled locally, you can omit auth entirely:
final client = await KalamClient.connect(url: 'http://localhost:8080');By default, connect() uses wsLazyConnect: true, so the shared WebSocket is opened on the first subscribe() call instead of immediately.
On native Dart and Flutter targets, subscription traffic also defaults to MessagePack over the shared Rust transport. That keeps the connect-to-first-batch path leaner than JSON without changing the cross-SDK Rust default.
For mobile apps that are live-query heavy, prefer:
final client = await KalamClient.connect(
url: 'http://localhost:8080',
authProvider: () async => Auth.jwt(await getJwtFromSecureStorage()),
wsLazyConnect: false,
);That warms the shared WebSocket during connect() instead of making the first live screen pay the socket setup cost.
First query
final result = await client.query('SELECT CURRENT_USER()');
if (!result.success) {
throw StateError('Query failed: ${result.error}');
}
print(result.rows.first);QueryResponse also includes timing metadata (tookMs) and can contain multiple result sets when you send multiple statements.
Rows are typed maps: Map<String, KalamCellValue>. Use accessors like asString(), asInt(), and asFile() instead of assuming positional arrays.
First live subscription
subscribe(...) returns a Stream<ChangeEvent>.
final stream = client.subscribe("SELECT * FROM app.messages WHERE room = 'main'");
final sub = stream.listen((event) {
switch (event) {
case AckEvent(:final subscriptionId):
print('Subscribed: $subscriptionId');
case InsertEvent(:final row):
print('New row: $row');
case SubscriptionError(:final code, :final message):
print('Error [$code]: $message');
default:
break;
}
});
// Later
await sub.cancel();For subscribe() and materialized live rows, use only SELECT ... FROM ... WHERE .... Apply ordering or row capping in your app after receiving the rows, and use lastRows when you need rewind behavior.
If you are targeting browser/WASM builds, verify the current release notes first. The native MessagePack default described here applies to the Rust-backed Dart client path.
Cleanup
await client.dispose();