spacetimedb
Dart SDK for SpacetimeDB. Real-time sync, BSATN codec, code generation, and offline-first support.
spacetimedb provides the runtime client, BSATN codec, and generator tooling needed to build type-safe Flutter/Dart apps on top of SpacetimeDB. It supports live table updates, reducer calls, authentication, and offline mutation replay.
Features
- WebSocket connection with reconnect handling and TLS support
- BSATN binary encoding/decoding for SpacetimeDB data types
- Generated, type-safe APIs for tables, reducers, enums, and views
- Real-time table cache with insert/update/delete streams
- Subscription API for SQL-based live queries
- Authentication utilities with token persistence support
- Offline-first mutation queue with optimistic updates
Installation
dependencies:
spacetimedb: ^0.1.0
Then install dependencies:
dart pub get
Quick Start
Generate a typed client from your SpacetimeDB module:
dart run spacetimedb:generate -s http://localhost:3000 -d your_database -o lib/generated
Use the generated client in your app:
import 'package:spacetimedb/spacetimedb.dart';
import 'generated/client.dart';
final client = await SpacetimeDbClient.connect(
host: 'localhost:3000',
database: 'your_database',
ssl: false,
authStorage: InMemoryTokenStore(),
initialSubscriptions: ['SELECT * FROM users'],
);
Usage
Connection
final client = await SpacetimeDbClient.connect(
host: 'localhost:3000',
database: 'your_database',
ssl: false,
authStorage: InMemoryTokenStore(),
);
client.connection.connectionStatus.listen((status) {
print('Connection status: $status');
});
Tables
for (final user in client.users.iter()) {
print('User: ${user.name}');
}
client.users.insertStream.listen((user) {
print('Inserted user: ${user.name}');
});
Reducers
final result = await client.reducers.createUser(name: 'Alice');
if (result.isSuccess) {
print('Reducer call succeeded');
}
Subscriptions
await client.subscriptions.subscribe([
'SELECT * FROM users WHERE active = true',
]);
Authentication
final client = await SpacetimeDbClient.connect(
host: 'spacetimedb.example.com',
database: 'app_db',
ssl: true,
authStorage: InMemoryTokenStore(),
);
print(client.identity?.toHexString);
Offline Support
final client = await SpacetimeDbClient.connect(
host: 'localhost:3000',
database: 'your_database',
offlineStorage: JsonFileStorage(basePath: '/tmp/spacetimedb_cache'),
);
print('Pending mutations: ${client.syncState.pendingCount}');
Code Generation
Use the bundled executable to generate strongly-typed Dart APIs:
dart run spacetimedb:generate -s http://localhost:3000 -d your_database -o lib/generated
You can also generate from a local module path:
dart run spacetimedb:generate -p path/to/spacetimedb-module -o lib/generated
API Overview
| API | Purpose |
|---|---|
SpacetimeDbClient.connect(...) |
Connect to a SpacetimeDB database and initialize generated APIs |
client.<table>.iter() |
Read cached table rows with typed iteration |
client.<table>.insertStream |
Listen for real-time inserts |
client.reducers.<name>(...) |
Call reducers with typed parameters/results |
client.subscriptions.subscribe([...]) |
Start additional live SQL subscriptions |
BsatnEncoder / BsatnDecoder |
Encode/decode BSATN payloads |
AuthTokenStore |
Plug in custom token persistence |
OfflineStorage |
Persist cached data and mutation queue for offline-first flows |
Platform Support
| Platform | Runtime | Code Generation | Offline (File) |
|---|---|---|---|
| Android | Yes | Yes | Yes |
| iOS | Yes | Yes | Yes |
| macOS | Yes | Yes | Yes |
| Windows | Yes | Yes | Yes |
| Linux | Yes | Yes | Yes |
| Web | Yes | N/A | No* |
* Web builds use InMemoryOfflineStorage. File-based JsonFileStorage requires dart:io and is not available on web. The SDK automatically provides a web-compatible stub that throws UnsupportedError if you try to use JsonFileStorage on web.
Security Considerations
- Offline storage is unencrypted. Table snapshots and pending mutations are stored as plaintext JSON. Do not persist sensitive data (passwords, tokens, PII) without app-level encryption.
- Use
ssl: truein production. Without SSL, authentication tokens are sent in plaintext over the network. - Web platform auth tokens are passed as URL query parameters (WebSocket API limitation). These tokens are short-lived, but may appear in proxy logs. Always use SSL in production.
- Token storage is pluggable via
AuthTokenStore. For production apps, implement a secure storage backend (e.g.,flutter_secure_storage).
Logging
By default, the SDK produces no log output. To enable logging:
// Option 1: Route to dart:developer (visible in DevTools)
SdkLogger.enableDeveloperLog();
// Option 2: Custom callback
SdkLogger.onLog = (level, message) {
// 'D' = debug, 'I' = info, 'W' = warning, 'E' = error
print('[$level] $message');
};
License
Apache License 2.0. See LICENSE.
Attribution
This project was originally forked from spacetimedb-dart-sdk by Mikael Wills. The original work provided the foundation for the WebSocket connection, BSATN codec, and initial code generation architecture.