Skip to content

Kotlin SDK ​

Use the Kotlin SDK for AYB auth, records, storage, and realtime (SSE + WebSocket).

Install ​

Preview — install from source. Registry publishing is tracked for GA.

kotlin
// settings.gradle.kts
// after cloning https://github.com/AllyourbaseHQ/allyourbase.git next to your app
include(":sdk_kotlin")
project(":sdk_kotlin").projectDir = file("../allyourbase/sdk_kotlin")

// app/build.gradle.kts
dependencies {
    implementation(project(":sdk_kotlin"))
}

Initialize ​

kotlin
import dev.allyourbase.AYBClient

val ayb = AYBClient("http://localhost:8090")

You can pass apiKey, custom transports (transport, sseTransport, wsTransport), tokenStore, timeout, maxRetries, and retryDelay via constructor params. Most SDK methods are suspend functions, so call them from a coroutine (for example, runBlocking or your app's existing coroutine scope).

Key model/data classes include AuthResponse, User, ListParams, ListResponse, BatchOperation, BatchResult, StorageObject, StorageListResponse, and RealtimeEvent.

Auth ​

kotlin
import kotlinx.coroutines.runBlocking

runBlocking {
    val registered = ayb.auth.register("[email protected]", "password")
    ayb.auth.login("[email protected]", "password")

    val me = ayb.auth.me()
    ayb.auth.refresh()
    ayb.auth.logout()
}

Passkey login composes AYB WebAuthn begin/finish calls with an authenticator supplied by your app. Keep AndroidX Credentials in the Android app module:

kotlin
import android.content.Context
import androidx.credentials.CredentialManager
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetPublicKeyCredentialOption
import androidx.credentials.PublicKeyCredential
import dev.allyourbase.PasskeyAuthenticator
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject

class AndroidPasskeyAuthenticator(
    private val credentialManager: CredentialManager,
    private val context: Context,
) : PasskeyAuthenticator {
    private val json = Json { ignoreUnknownKeys = true }

    override suspend fun createAssertion(options: JsonObject): JsonObject {
        val request = GetCredentialRequest.Builder()
            .addCredentialOption(GetPublicKeyCredentialOption(requestJson = options.toString()))
            .build()
        val credential = credentialManager.getCredential(context, request).credential as PublicKeyCredential
        return json.parseToJsonElement(credential.authenticationResponseJson).jsonObject
    }
}

runBlocking {
    val auth = ayb.auth.signInWithPasskey(
        "[email protected]",
        AndroidPasskeyAuthenticator(CredentialManager.create(context), context),
    )
}

The sdk_kotlin module is pure JVM: it does not depend on androidx.credentials, perform on-device biometric validation, or ship a packaged Android credentials module.

Listen for auth changes:

kotlin
val unsubscribe = ayb.onAuthStateChange { event, session ->
    println("$event sessionPresent=${session != null}")
}

// later
unsubscribe()

Records ​

kotlin
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.coroutines.runBlocking

runBlocking {
    val created = ayb.records.create(
        "posts",
        buildJsonObject { put("title", "Hello") }
    )

    val post = ayb.records.get("posts", "42")

    val updated = ayb.records.update(
        "posts",
        "42",
        buildJsonObject { put("title", "Updated") }
    )

    val list = ayb.records.list(
        "posts",
        params = dev.allyourbase.ListParams(filter = "published=true", sort = "-created_at", perPage = 20)
    )

    ayb.records.delete("posts", "42")
}

Batch:

kotlin
import dev.allyourbase.BatchOperation
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.coroutines.runBlocking

runBlocking {
    val batchResults = ayb.records.batch(
        "posts",
        listOf(
            BatchOperation(method = "create", body = buildJsonObject { put("title", "A") }),
            BatchOperation(method = "update", id = "42", body = buildJsonObject { put("title", "B") }),
        )
    )
}

Realtime (SSE) ​

kotlin
val stop = ayb.realtime.subscribe(listOf("posts", "comments")) { event ->
    println("${event.action} ${event.table}")
}

// later
stop()

You can also consume as Flow:

kotlin
val flow = ayb.realtime.subscribeFlow(listOf("posts"))

Realtime (WebSocket) ​

kotlin
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.coroutines.runBlocking

runBlocking {
    ayb.realtime.connectWebSocket()

    val stopRows = ayb.realtime.subscribeWS(listOf("posts")) { event ->
        println(event.record)
    }

    val leaveChannel = ayb.realtime.channelSubscribe("room:lobby")

    val removeBroadcastListener = ayb.realtime.onBroadcast("room:lobby") { event, payload ->
        println("$event $payload")
    }

    ayb.realtime.broadcast(
        channel = "room:lobby",
        event = "chat.message",
        payload = buildJsonObject { put("text", "hello") },
        includeSelf = true,
    )

    ayb.realtime.presenceTrack(
        channel = "room:lobby",
        state = buildJsonObject { put("name", "android") },
    )

    val presences = ayb.realtime.presenceSync("room:lobby")
    ayb.realtime.presenceUntrack("room:lobby")

    // cleanup
    stopRows()
    leaveChannel()
    removeBroadcastListener()
    ayb.realtime.disconnectWebSocket()
}

Storage ​

kotlin
import kotlinx.coroutines.runBlocking

runBlocking {
    val uploaded = ayb.storage.upload(
        bucket = "docs",
        data = "hello".encodeToByteArray(),
        name = "hello.txt",
        contentType = "text/plain",
    )

    val downloadUrl = ayb.storage.downloadUrl("docs", uploaded.name)
    val signedUrl = ayb.storage.getSignedUrl("docs", uploaded.name, expiresIn = 3600)
    val listing = ayb.storage.list("docs", prefix = "hel", limit = 20)
    ayb.storage.delete("docs", uploaded.name)
}

Errors ​

AYBException fields: status, message, code, data, docUrl.

kotlin
import dev.allyourbase.AYBException
import kotlinx.coroutines.runBlocking

try {
    runBlocking {
        ayb.records.get("posts", "missing")
    }
} catch (e: AYBException) {
    println("${e.status} ${e.code} ${e.message}")
    println(e.data)
    println(e.docUrl)
}

Released under the MIT License.