Client Lifecycle
One-time initialization
Call KalamClient.init() once at app startup. It initializes the underlying Rust runtime.
await KalamClient.init();Do not call KalamClient.connect(...) before init().
Creating a client
final client = await KalamClient.connect(
url: 'http://localhost:8080',
authProvider: () async => Auth.jwt(await getJwt()),
timeout: const Duration(seconds: 30),
maxRetries: 3,
disableCompression: false,
logLevel: Level.debug,
logListener: (entry) => debugPrint(entry.toString()),
);Notes:
connect(...)returns a ready-to-use handle. The SDK manages the WebSocket connection lifecycle automatically.- Most methods use HTTP; subscriptions additionally use WebSocket under the hood.
- With
wsLazyConnect: true(the default),connect()does not open the shared WebSocket immediately. - On native Dart targets, the shared subscription connection defaults to MessagePack serialization for lower overhead on first subscription and live updates.
wsLazyConnect (default: true)
By default, the WebSocket connection is lazy: it is deferred until the
first subscribe() call. This avoids unnecessary connections when the client
is only used for HTTP queries.
Set wsLazyConnect: false to establish the connection eagerly:
final client = await KalamClient.connect(
url: 'http://localhost:8080',
authProvider: () async => Auth.jwt(await getJwt()),
wsLazyConnect: false, // connect WebSocket immediately
);Auth refresh model
authProvideris the connect-time auth API.connect()resolves auth once up front, and the first lazysubscribe()reuses those already-resolved credentials.- Use
refreshAuth()to proactively re-runauthProviderand push updated credentials into the client. - Return
Auth.basic(...)if you want the SDK to perform a Basic-to-JWT exchange before first use.
Refreshing auth in place
If you provided an authProvider, you can re-fetch and push updated credentials into the client:
await client.refreshAuth();
Timer.periodic(const Duration(minutes: 55), (_) => client.refreshAuth());With the default Auth.none() provider, refreshAuth() simply re-resolves anonymous auth.
Manual WebSocket controls
The client also exposes a few explicit shared-socket controls:
isConnectedreturns whether the shared WebSocket is currently open.disconnectWebSocket()closes the shared WebSocket.reconnectWebSocket()first tries a fast reconnect with the current auth already held in memory. If the server rejects that reconnect for auth reasons, the SDK refreshes auth once and retries.
final connected = await client.isConnected;
if (!connected) {
await client.reconnectWebSocket();
}Mobile live-connection pattern
For Flutter apps with live screens, keep one KalamClient alive for the whole signed-in session and reconnect it when the app returns to the foreground.
class LiveClientController with WidgetsBindingObserver {
final KalamClient client;
LiveClientController(this.client);
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
client.reconnectWebSocket();
}
}
}That avoids waiting for a stale socket to be detected passively and is the fastest path back to a live subscription after resume.
Connection handlers
Use connectionHandlers to receive lifecycle events (connect/disconnect/errors) and optional raw message debugging.
final client = await KalamClient.connect(
url: 'http://localhost:8080',
authProvider: () async => Auth.jwt(await getJwt()),
connectionHandlers: ConnectionHandlers(
onConnect: () => print('connected'),
onDisconnect: (reason) => print('disconnected: ${reason.message}'),
onError: (error) => print('error: ${error.message}'),
onReceive: (message) => print('[recv] $message'),
onSend: (message) => print('[send] $message'),
),
);Handlers are only active when you pass at least one callback.
Use onReceive / onSend only for local debugging; avoid logging sensitive data (tokens, PII) in production.
SDK logging level and redirection
KalamClient.connect(...) accepts:
logLevel: Level?(frompackage:logger/logger.dart)logListener: LogListener?
Example:
import 'package:logger/logger.dart' show Level;
final client = await KalamClient.connect(
url: 'http://localhost:8080',
authProvider: () async => Auth.jwt(await getJwt()),
logLevel: Level.info,
logListener: (entry) {
myLogger.i('[${entry.tag}] ${entry.message}');
},
);If no logListener is provided, logs are emitted with print(...) and appear in flutter run/Logcat.
Disposing
Call dispose() when the client is no longer needed:
await client.dispose();After disposing, do not call query() or subscribe() on the same instance.
If you keep a single client for the whole app lifetime, dispose it only when the app is shutting down.