Skip to content

Dart SDK

Package: kataflax_client_sdk. Same surface as @kataflax/sdk and kataflax-sdk: project auth, collections, queries, files. It does not manage orgs or schemas.

Import package:kataflax_client_sdk/kataflax_client_sdk.dart.

kataflax_client_sdk has publish_to: none. It is not on pub.dev. Depend on the package directory and adjust path to the app:

dependencies:
kataflax_client_sdk:
path: ../kataflax_sdks/dart/sdk

Flutter covers --dart-define and keeping a service token out of the app binary.

import 'package:kataflax_client_sdk/kataflax_client_sdk.dart';
void main() async {
final client = KataflaxClient(
baseUrl: 'https://api.tefily.com',
projectId: 'YOUR_PROJECT_ID',
);
final auth = await client.auth.login(
email: 'user@example.com',
password: 'password',
);
print('Logged in as ${auth.user['email']}');
final posts = client.collection('posts');
final created = await posts.create({
'title': 'Hello World',
'status': 'draft',
});
final many = await posts.createMany([
{'title': 'Hello', 'status': 'draft'},
{'title': 'World', 'status': 'draft'},
]);
final all = await posts.list(page: 1, pageSize: 20);
print('Total posts: ${all.total}');
final post = await posts.get(created['_id'] as String);
await posts.update(post['_id'] as String, {'title': 'Updated title'});
await posts.delete(post['_id'] as String);
client.close();
}
await client.auth.register(
email: 'jane@example.com',
password: 'secret123',
extraFields: {'name': 'Jane'},
);
// Confirm the email via the Tefily link, then:
await client.auth.login(email: 'jane@example.com', password: 'secret123');
print(client.token);
client.setToken('eyJhbGciOi...'); // platform JWT or PAT. Not for mobile/web clients
final profile = await client.auth.me();

setToken stores a platform JWT that bypasses end-user rules, or a personal access token. Client apps should use project login.

End-user auth covers the confirmation email, password length, and the fact that register does not return a JWT.

resendVerification, verifyEmail, requestPasswordReset, and completePasswordReset are on auth.

A client with a serviceToken can send mail from the project’s own address with email.send. See Send email.

await backend.email.send(
to: 'jane@example.com',
subject: 'Your order shipped',
html: '<p>It is on the way.</p>',
replyTo: 'help@example.com',
);

Provide html, text, or both. The From address is fixed by the project.

A backend client takes serviceToken and calls auth.verify. The full page is Service tokens. login on that client replaces kfxs_… with a project JWT, so keep a separate client for the service token.

final backend = KataflaxClient(
baseUrl: 'https://api.tefily.com',
projectId: 'YOUR_PROJECT_ID',
serviceToken: 'kfxs_…', // never ship to a client app
);
final checked = await backend.auth.verify(incomingUserJwt);

auth.verify returns ({bool valid, Map<String, dynamic>? user}).

where takes named parameters (isEqualTo:, and the other operators), not an options object. Null is exported from the barrel. Use Null.value when the filter must be JSON null. A Dart null omits the operator.

final results = await client
.collection('products')
.where('price', isGreaterThanOrEqualTo: 10)
.where('price', isLessThan: 100)
.where('category', isIn: ['electronics', 'books'])
.orderBy('price')
.orderBy('_createdAt', descending: true)
.list(pageSize: 50);

Chained where is $and. orderBy('name') is ascending (1); descending: true is -1.

select(['title']) returns only those fields (plus _id).

join('authorId', from: 'users', as: 'author') embeds matching related documents as an array under author (default limit 50, max 100).

expand('authorId') uses a reference field’s optional target collection.

select, join, and expand are chainable on Query (and as Collection entry points). Collection.get(id) returns the full document. Query.get(id) is the call that honors select, join, and expand.

Operator names and caps are on Query.

updateMany and deleteMany require at least one where. They use the same encoded filter as list.

final modified = await client
.collection('posts')
.where('status', isEqualTo: 'draft')
.updateMany({'status': 'archived'});
final deleted = await client
.collection('posts')
.where('status', isEqualTo: 'archived')
.deleteMany();

Query documents the 100-item cap and the “at least one where” rule. createMany is in the quickstart.

On a server or VM, File needs import 'dart:io';. A Flutter app passes its own byte stream; this SDK has no Flutter-only upload API.

final bytes = await File('photo.jpg').readAsBytes();
final meta = await posts.uploadFile(
recordId,
'attachment',
data: Stream.value(bytes),
length: bytes.length,
filename: 'photo.jpg',
contentType: 'image/jpeg',
);
final download = await posts.getDownloadUrl(recordId, 'attachment', meta.id);
await posts.deleteFile(recordId, 'attachment', meta.id);

Files covers the presign, PUT, and complete steps.

try {
await client.collection('posts').get('nonexistent');
} on KataflaxException catch (e) {
print(e.statusCode);
print(e.message);
print(e.errors);
}