Skip to main content

aquabase 0.6.5 copy "aquabase: ^0.6.5" to clipboard
aquabase: ^0.6.5 copied to clipboard

Flutter SDK for Aquabase — encrypted real-time database with offline sync, tags, and binary transport.

Aquabase Flutter SDK #

Encrypted real-time database for Flutter. Offline-first with automatic cloud sync, binary transport, and zero code generation.

Install #

flutter pub add aquabase

Or add to pubspec.yaml:

dependencies:
  aquabase: ^0.5.5

Quick Start #

import 'package:aquabase/aquabase.dart';

final app = await Aquabase.init(
  projectId: 'your_project_id',
  apiKey: 'aq_pub_...',
);

// Database (instant local cache + background sync)
await app.collection('users').doc('u1').set({'name': 'Ana', 'age': 25});
final user = await app.collection('users').doc('u1').get();

// Auth
final result = await app.auth.login('user@example.com', 'password123');

// Storage
await app.storage.upload('avatars', 'photo.jpg', bytes);

// Logs
await app.logs.connect();
app.logs.info('db', 'User created account');

How It Works #

  1. All reads/writes go to the local cache — instant, no network latency
  2. When online, changes sync to the server in background
  3. When offline, failed ops queue to disk automatically
  4. On reconnect, the queue flushes to the server — no data loss

Collections #

final users = app.collection('users');

await users.doc('u1').set({'name': 'Ana'});
final user = await users.doc('u1').get();
await users.doc('u1').delete();

Bulk Operations #

await users.bulkSet({
  'u1': {'name': 'Ana'},
  'u2': {'name': 'Luis'},
  'u3': {'name': 'Carlos'},
});

final results = await users.bulkGet(['u1', 'u2', 'u3']);
await users.bulkDelete(['u1', 'u2', 'u3']);

Real-Time #

Watch a document or a query for changes — emits current data immediately, then on every update from any device.

// Watch a single document
final sub = users.watch('u1').listen((user) {
  if (user != null) renderUser(user);
});

// Watch a tag query
final sub2 = users.watch({'status': 'active'}).listen((results) {
  results.forEach((id, data) => print('$id: $data'));
});

// Stop watching
sub.cancel();
sub2.cancel();

Secondary Index (Tags) #

Tag documents with field-value pairs and query them with AND logic. Tags are kept in a RAM index on the server — queries are instant.

final users = app.collection('users');

// Auto-generated ID (like Firebase .add())
final docId = await users.setWithTags(null, {'name': 'Ana'}, {
  'status': 'active',
  'role': 'admin',
});
// docId = '1710367200123456_a7f3'

// Custom ID (optional)
await users.setWithTags('u1', {'name': 'Ana'}, {
  'status': 'active',
  'role': 'admin',
});

// Query: returns only IDs (fast — no disk I/O)
final ids = await users.query({'status': 'active', 'role': 'admin'});

// Hydrate only what you need
final docs = await users.bulkGet(ids);

// Or get IDs + data in one call
final results = await users.queryWithData({'status': 'active'});

Cleanup is automatic: doc.delete() and doc.set() (without tags) remove the document from all indexes.

Local Collections #

Keep data only on the device — no server sync, no offline queue. Useful for caching data from external sources (Firebase, REST APIs, etc).

// Normal collection — syncs to server
final attendances = app.collection('attendances');

// Local collection — data stays on the device only
final cache = app.collection('students_cache', local: true);

// Same API, zero server interaction
await cache.doc('s1').set({'name': 'Ana', 'qr': 'ABC123'});
final student = await cache.doc('s1').get();
await cache.doc('s1').delete();

// Bulk operations also stay local
await cache.bulkSet({
  's1': {'name': 'Ana'},
  's2': {'name': 'Luis'},
});

Local collections use the same L1 (SIEVE memory) + L2 (disk) cache as normal collections. They persist across app restarts but never touch the network.

Note: A collection name cannot be both local and remote simultaneously. Attempting to create collection('users') and collection('users', local: true) will trigger an assertion error.

Date Handling #

DateTime objects are automatically serialized as milliseconds since epoch (UTC). On read, timestamps are returned as int — convert in your app:

// Write
await users.doc('u1').set({
  'name': 'Ana',
  'createdAt': DateTime.now(),
});

// Read
final user = await users.doc('u1').get();
final date = DateTime.fromMillisecondsSinceEpoch(user!['createdAt'], isUtc: true);

This format is cross-platform compatible with the Node/Web SDK.

Offline-First #

Works without connection. Writes go to local cache and queue for sync.

await app.collection('users').doc('u1').set({'name': 'Ana'});

// Check pending ops
print(app.pendingOfflineOps);

// On reconnect, queue flushes automatically
// Or flush manually:
await app.flushOfflineQueue();

Encryption #

final app = await Aquabase.init(
  projectId: 'your_project_id',
  apiKey: 'aq_pub_...',
  enableCrypto: true, // AES-256-GCM
);

Custom Server URL #

final app = await Aquabase.init(
  projectId: 'your_project_id',
  apiKey: 'aq_pub_...',
  url: 'http://localhost:3280',
);

Auth #

// Email/password
final result = await app.auth.register('user@example.com', 'password123');
final login = await app.auth.login('user@example.com', 'password123');

// OAuth (Google, GitHub)
final google = await app.auth.signInWithOAuth(OAuthProvider.google, googleIdToken);
final github = await app.auth.signInWithOAuth(OAuthProvider.github, githubCode);

// Reconnect with user identity
final userApp = await Aquabase.init(
  projectId: 'your_project_id',
  apiKey: 'aq_pub_...',
  jwt: result.token,
);

Storage #

await app.storage.createBucket(name: 'avatars', public: true);

final bytes = await File('photo.jpg').readAsBytes();
await app.storage.upload('avatars', 'user1.jpg', bytes, contentType: 'image/jpeg');

final files = await app.storage.listFiles('avatars');
final data = await app.storage.download('avatars', 'user1.jpg');
await app.storage.deleteFile('avatars', 'user1.jpg');

Logs #

await app.logs.connect();

app.logs.info('db', 'User created account');
app.logs.warn('auth', 'Invalid password attempt', source: '192.168.1.1');
app.logs.error('ws', 'Connection timeout');

final records = await app.logs.query(LogQueryOptions(
  since: DateTime.now().subtract(Duration(hours: 1)).microsecondsSinceEpoch * 1000,
  minLevel: LogLevel.warn,
  channel: 'auth',
  limit: 100,
));

Crash Capture #

Enabled by default when connect() is called. Unhandled exceptions and Flutter errors are sent to the server automatically.

await app.logs.connect(); // Crashes captured automatically

API Reference #

Aquabase #

Method Description
Aquabase.init(...) Initialize with named parameters
Aquabase.instance Global access after init
collection(name) Get a collection (synced)
collection(name, local: true) Get a local-only collection
isConnected WebSocket connection status
pendingOfflineOps Pending offline operations count
flushOfflineQueue() Manually sync pending ops
connectionState Stream of connection changes
deniedOperations Stream of blockIds rejected by security rules
flushResults Stream of FlushResult after each sync
dispose() Release resources

Init Options #

Parameter Type Default Description
projectId String — Project ID (required)
apiKey String — API key (required)
url String Aquabase cloud Server URL
jwt String null JWT for authenticated users
enableCrypto bool false Enable AES-256-GCM encryption
enableCache bool true Enable L1/L2 local cache

Collection #

Method Description
doc(id) Document reference
bulkSet(docs) Batch write
bulkGet(ids) Batch read
bulkDelete(ids) Batch delete
setWithTags(id?, data, tags) Write with tags. ID auto-generated if null. Returns docId
query(tags) Query index → IDs only (fast)
queryWithData(tags) Query index → IDs + data
generateId() Generate a unique document ID
watch('id') Real-time doc stream. Returns Stream
watch({tags}) Real-time query stream. Returns Stream
isLocal Whether the collection is local-only

Document #

Method Description
set(data) Write to cache + sync (or cache-only if local)
get() Read from cache, fallback server (cache-only if local)
delete() Delete from cache + sync (or cache-only if local)

Auth #

Method Description
app.auth.register(email, password) Register user, returns JWT + uid
app.auth.login(email, password) Login user, returns JWT + uid
app.auth.signInWithOAuth(provider, credential) OAuth login (Google/GitHub), auto-registers
app.auth.refresh(token) Refresh an expired JWT

Storage #

Method Description
app.storage.listBuckets() List all buckets
app.storage.createBucket(name, compression?, pub?) Create a new bucket
app.storage.deleteBucket(name) Delete a bucket and all its files
app.storage.listFiles(bucket) List files in a bucket
app.storage.upload(bucket, path, bytes, type?) Upload a file (overwrites)
app.storage.download(bucket, path) Download file as bytes
app.storage.deleteFile(bucket, path) Delete a file

Logs #

Method Description
app.logs.connect() Connect + enable crash capture
app.logs.info(channel, msg) Push info-level log
app.logs.warn(channel, msg) Push warn-level log
app.logs.error(channel,msg) Push error-level log
app.logs.flush() Flush buffer to server
app.logs.query(opts?) Query stored logs
app.logs.dispose() Flush + disconnect

Architecture #

Component Implementation
Serialization MsgPack — DateTime → ms epoch auto-conversion
L1 Cache SIEVE eviction (NSDI '24) — lazy promotion
L2 Storage CompactCache — read-only snapshot + append-only disk
Cloud Sync WebSocket with auto-reconnect + backoff
Offline Queue Persisted to disk, auto-flush on reconnect
Encryption AES-256-GCM

License #

Proprietary

0
likes
0
points
118
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter SDK for Aquabase — encrypted real-time database with offline sync, tags, and binary transport.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

android_id, cryptography, device_info_plus, flutter, msgpack_dart, package_info_plus, path_provider, web_socket_channel

More

Packages that depend on aquabase