Skip to Content

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

  • authProvider is the connect-time auth API.
  • connect() resolves auth once up front, and the first lazy subscribe() reuses those already-resolved credentials.
  • Use refreshAuth() to proactively re-run authProvider and 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:

  • isConnected returns 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? (from package: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.

Next

Last updated on