RafikiDB Dart SDK#

sdk-dart

Use when writing Dart or Flutter code with the RafikiDB Dart SDK (rafikidb on pub.dev). Covers RafikiDB client, DataBuilder filters/joins/cursor pagination, auth with session persistence (SessionStore, shared_preferences), realtime (Centrifugo/SSE), storage, env, secrets, webhooks, functions, payments.

You are working with the rafikidb Dart package (pub.dev, pure Dart, works in Flutter, server and CLI). Install: dart pub add rafikidb.

Setup#

import 'package:rafikidb/rafikidb.dart';

final db = RafikiDB(
  projectId: '5c73dab0-...',
  apiKey: 'raf_live_...',
  baseUrl: 'https://api.rafikidb.com/api/v1', // optional
  persistSession: true, // file store under ~/.rafikidb/{projectId}.json
);
DART
  • Every call returns Envelope<T> with success, message, data?, errors?.
  • Failures throw RafikiDBError with status, code (RafikiDBErrorCode enum) and errors.
  • persistSession: true uses a FileSessionStore (pure Dart). In Flutter, pass a custom SessionStore backed by shared_preferences.

Data#

final rows = await db
    .from('profiles')
    .select('id, nationality')
    .eq('nationality', 'Tanzania')
    .gt('age', 18)
    .inList('region', ['dar', 'mba'])
    .order('created_at', ascending: false)
    .limit(25)
    .execute();
DART
  • Filters: eq, neq, gt, gte, lt, lte, like, ilike, isNull, isNotNull, inList.
  • Pagination: limit, offset, cursor(id) (keyset, for large tables).
  • Single row: .get(id); first row or null: .single(); count: .head().

Joins (no SQL, via query engine)#

final rows = await db
    .from('messages')
    .select('id, message, users.full_name')
    .join(JoinSpec(
      table: 'users',
      fromColumn: 'user_id',
      toColumn: 'id',
      type: 'LEFT JOIN', // INNER | LEFT | RIGHT | FULL
    ))
    .limit(20)
    .execute();
DART

Joined columns appear as {table}.{column}. Joins route through POST /projects/{id}/query/run.

Writes#

final created = await db.from('profiles').insert({
  'full_name': 'Asha Mwinyi',
  'nationality': 'Tanzania',
});

// update/delete are scoped with filters FIRST (they execute immediately)
await db.from('profiles').eq('id', id).update({'nationality': 'Kenya'});
await db.from('profiles').eq('id', id).delete();
DART

update() / delete() require an eq('id', ...) filter, else they throw a StateError.

Auth (project users, not dashboard)#

final created = await db.auth.signup(SignupOptions(
  email: 'asha@example.com',
  password: 'strong-pass1',
  fullName: 'Asha Mwinyi',
  phone: '+255712345678',
));

final session = await db.auth.login(SigninOptions(email: ..., password: ...));

await db.auth.otpRequest('+255712345678');
await db.auth.otpVerify(phone: ..., code: '123456', fullName: 'Asha');

await db.auth.resetPassword(email);
await db.auth.confirmResetPassword(email: ..., code: ..., newPassword: ...);

db.auth.signOut();
await db.auth.refresh(refreshToken);
await db.auth.logout(refreshToken);
DART
  • Login/signup/OTP-verify auto-store the session; every request then carries the Bearer token so RLS sees the authenticated user.
  • Session persistence: persistSession: true (file) or a custom store:
class PrefsSessionStore implements SessionStore {
  PrefsSessionStore(this.prefs);
  final SharedPreferences prefs;

  
  Session? read() {
    final raw = prefs.getString('rafikidb_session');
    return raw == null ? null : Session.fromJson(jsonDecode(raw));
  }

  
  void write(Session? session) {
    if (session == null) {
      prefs.remove('rafikidb_session');
    } else {
      prefs.setString('rafikidb_session', jsonEncode(session.toJson()));
    }
  }
}
DART
  • React to changes: db.sessionStream.listen((s) {}) (emits null on sign-out) or db.subscribeSession((s) {}).
  • Dashboard login (RafikiDB account holders only): db.auth.platformLogin(email:, password:).

Realtime#

final sub = db.realtime.subscribe(
  'messages',
  (event) => print('${event.type}: ${event.record}'),
  options: const SubscribeOptions(
    events: ['INSERT', 'DELETE'],            // optional
    transport: RealtimeTransport.auto,       // auto | centrifugo | sse
  ),
);
sub.unsubscribe();
DART
  • event is a RealtimeEvent: { id, type, table, projectId, record, oldRecord?, createdAt }.
  • auto/centrifugo use WebSocket via Centrifugo (POST /realtime/connect, v6 wire: send {"id": 1, "connect": {"token": token}}); sse uses a plain HTTP stream. Both auto-reconnect with exponential backoff (1s..30s).

Modules#

// Storage
await db.storage.createBucket(name: 'Avatars', slug: 'avatars', isPublic: true, fileSizeLimit: 5 * 1024 * 1024);
await db.storage.listBuckets();
await db.storage.signedUploadUrl(bucketId: b['id'], objectName: 'user-1.png');
await db.storage.signedDownloadUrl(objectId);
db.storage.publicUrl(bucketId, objectId);

// Env vars
await db.env.set('STRIPE_KEY', 'sk_test_123', environment: 'production');
await db.env.bulkSet('development', {'DEBUG': 'true'});

// Secrets (write-only)
await db.secrets.set(key: 'API_SECRET', value: 's3cr3t', description: '...');
await db.secrets.reveal(secretId);

// Webhooks
await db.webhooks.create(name: 'Order', url: 'https://myapp.com/hooks/orders', events: ['order.created'], secret: 'whsec_...');
await db.webhooks.listDeliveries(webhookId);

// Edge functions
await db.functions.create(name: 'hello', runtime: 'javascript', code: '...');
await db.functions.deploy(fnId);
await db.functions.invoke(fnId, method: 'POST', body: '{"name":"Asha"}');

// Payments (Snippe + M-Pesa)
await db.payments.stkPush(phone: '+255712345678', amount: 5000, description: 'Order #123');
await db.payments.snippeSession(amount: 15000, redirectUrl: 'https://myapp.com/cb', orderId: 'o1');
await db.payments.snippeStatus(reference);
DART

Flutter pattern#

StreamBuilder<Session?>(
  stream: db.sessionStream,
  builder: (context, snapshot) {
    final session = snapshot.data ?? db.session;
    if (session == null) return const SignInForm();
    return Text('Welcome, ${session.user.fullName}');
  },
)
DART

Gotchas#

  • update/delete throw unless .eq('id', ...) is set first (filters chain before the write call).
  • Dashboard auth (platformLogin) is NOT for app users; app auth is project-scoped.
  • persistSession writes under ~/.rafikidb/ by default; use a custom SessionStore for Flutter.