11 |
12 |
13 |
--------------------------------------------------------------------------------
/Supabase/src/jsTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.JS, CurrentPlatformTarget, "The current platform target should be WEB")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/koin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.KoinApplication
4 | import org.koin.core.context.startKoin
5 |
6 | fun initKoin(additionalConfiguration: KoinApplication.() -> Unit = {}) {
7 | startKoin {
8 | modules(supabaseModule, netModule, viewModelModule)
9 | additionalConfiguration()
10 | }
11 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/src/jsMain/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestErrorResponse.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import kotlinx.serialization.Serializable
4 | import kotlinx.serialization.json.JsonElement
5 |
6 | @Serializable
7 | internal data class PostgrestErrorResponse(
8 | val message: String,
9 | val hint: String? = null,
10 | val details: JsonElement? = null,
11 | val code: String? = null,
12 | )
13 |
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/SignedUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Represents a signed url
7 | * @param error An optional error message
8 | * @param signedURL The signed url
9 | * @param path The path of the file
10 | */
11 | @Serializable
12 | data class SignedUrl(val error: String? = null, val signedURL: String, val path: String)
13 |
--------------------------------------------------------------------------------
/Supabase/src/iosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.IOS, CurrentPlatformTarget, "The current platform target should be IOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/tvosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.TVOS, CurrentPlatformTarget, "The current platform target should be TVOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Auth/src/webMain/kotlin/io/github/jan/supabase/auth/Utils.wasmJs.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import io.ktor.util.PlatformUtils.IS_BROWSER
5 | import kotlinx.browser.window
6 |
7 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
8 | if(IS_BROWSER) {
9 | window.location.href = url
10 | } else {
11 | //TODO: Unsupported for now
12 | }
13 | }
--------------------------------------------------------------------------------
/Supabase/src/linuxTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.LINUX, CurrentPlatformTarget, "The current platform target should be LINUX")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/macosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.MACOS, CurrentPlatformTarget, "The current platform target should be MACOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/androidUnitTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.ANDROID, CurrentPlatformTarget, "The current platform target should be ANDROID")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/mingwX64Test/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.WINDOWS, CurrentPlatformTarget, "The current platform target should be WINDOWS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/wasmJsTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.WASM_JS, CurrentPlatformTarget, "The current platform target should be WASM_JS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/watchosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.WATCHOS, CurrentPlatformTarget, "The current platform target should be WATCHOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/demos/android-login/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.AppViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = AppViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/TestUtils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.testing
2 |
3 | import io.ktor.http.HttpMethod
4 | import kotlin.test.assertEquals
5 |
6 | fun assertMethodIs(expected: HttpMethod, actual: HttpMethod) {
7 | assertEquals(expected, actual, "Method should be $expected")
8 | }
9 |
10 | fun assertPathIs(expected: String, actual: String) {
11 | assertEquals(expected, actual, "Path should be '$expected'")
12 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.UploadViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = UploadViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.AppViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = AppViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/Order.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query
2 |
3 | /**
4 | * Used to order the result of a query
5 | * @param value The value to be used in the query
6 | */
7 | enum class Order(val value: String) {
8 | /**
9 | * Order the data ascending
10 | */
11 | ASCENDING("asc"),
12 |
13 | /**
14 | * Order the data descending
15 | */
16 | DESCENDING("desc");
17 | }
18 |
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/FileUploadResponse.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | /**
4 | * The response of a file upload
5 | * @param id The id of the file
6 | * @param path The path to the file. Can be used as is in [BucketApi] uploading methods
7 | * @param key The key of the file
8 | */
9 | data class FileUploadResponse(
10 | val id: String? = null,
11 | val path: String,
12 | val key: String? = null
13 | )
14 |
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.AppViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = AppViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/Auth/src/mingwMain/kotlin/io/github/jan/supabase/auth/Utils.mingw.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import kotlinx.cinterop.ExperimentalForeignApi
5 | import platform.windows.SW_SHOWNORMAL
6 | import platform.windows.ShellExecuteW
7 |
8 | @OptIn(ExperimentalForeignApi::class)
9 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
10 | ShellExecuteW(null, "open", url, null, null, SW_SHOWNORMAL);
11 | }
--------------------------------------------------------------------------------
/demos/android-login/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
2 | pluginManagement {
3 | repositories {
4 | google()
5 | gradlePluginPortal()
6 | mavenCentral()
7 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
8 | }
9 | }
10 |
11 | rootProject.name = "android-login"
12 |
13 | include(":android", ":desktop", ":web", ":common")
14 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.ChatViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = ChatViewModel(get(), get(), get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/chatdemoiosApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // chatdemoiosApp.swift
3 | // chatdemoios
4 | //
5 | // Created by Hieu Vu on 23/12/2023.
6 | //
7 |
8 | import SwiftUI
9 | import common
10 |
11 | @main
12 | struct chatdemoiosApp: App {
13 |
14 | init() {
15 | KoinKt.doInitKoin(additionalConfiguration: {_ in})
16 | }
17 |
18 | var body: some Scene {
19 | WindowGroup {
20 | ContentView()
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Auth/src/jvmMain/kotlin/io/github/jan/supabase/auth/Utils.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import kotlinx.coroutines.Dispatchers
5 | import kotlinx.coroutines.withContext
6 | import java.awt.Desktop
7 | import java.net.URI
8 |
9 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
10 | withContext(Dispatchers.IO) {
11 | Desktop.getDesktop()
12 | .browse(URI(url))
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Auth/src/nonDesktopMain/kotlin/io/github/jan/supabase/auth/Utils.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("RedundantSuspendModifier")
2 | package io.github.jan.supabase.auth
3 |
4 | import io.github.jan.supabase.auth.user.UserSession
5 |
6 | internal actual suspend fun Auth.startExternalAuth(
7 | redirectUrl: String?,
8 | getUrl: suspend (redirectTo: String?) -> String,
9 | onSessionSuccess: suspend (UserSession) -> Unit
10 | ) {
11 | config.urlLauncher.openUrl(supabaseClient, getUrl(redirectUrl))
12 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/HttpRequestException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.exceptions
2 |
3 | import io.ktor.client.request.HttpRequestBuilder
4 | import kotlinx.io.IOException
5 |
6 | /**
7 | * An exception that is thrown when a request fails due to network issues
8 | */
9 | class HttpRequestException(message: String, request: HttpRequestBuilder): IOException("HTTP request to ${request.url.buildString()} (${request.method.value}) failed with message: $message")
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/mfa/MfaStatus.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.mfa
2 |
3 | /**
4 | * Represents the MFA status of a user.
5 | * @property enabled Whether MFA is enabled for the user. If true, the user can log in using MFA and has at least one verified factor.
6 | * @property active Whether MFA is active for the user. If true, the user is logged in using MFA.
7 | */
8 | data class MfaStatus(
9 | val enabled: Boolean,
10 | val active: Boolean
11 | )
12 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/RealtimeMessage.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonObject
6 |
7 | /**
8 | * Represents a message retrieved by the [RealtimeChannel]
9 | */
10 | @Serializable
11 | @SupabaseInternal
12 | data class RealtimeMessage(val topic: String, val event: String, val payload: JsonObject, val ref: String?)
--------------------------------------------------------------------------------
/Auth/src/commonTest/kotlin/PlatformSetupTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.Auth
2 | import io.github.jan.supabase.auth.auth
3 | import io.github.jan.supabase.auth.minimalConfig
4 | import io.github.jan.supabase.testing.createMockedSupabaseClient
5 |
6 | internal fun createMinimalAuthClient(
7 | autoSetup: Boolean,
8 | ) = createMockedSupabaseClient(
9 | configuration = {
10 | install(Auth) {
11 | autoSetupPlatform = autoSetup
12 | minimalConfig()
13 | }
14 | }
15 | ).auth
16 |
--------------------------------------------------------------------------------
/Postgrest/src/jvmMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.SerialName
5 | import kotlin.reflect.KProperty1
6 | import kotlin.reflect.full.findAnnotation
7 |
8 | @SupabaseInternal
9 | actual fun
getSerialName(property: KProperty1): String {
10 | val serialName = property.findAnnotation()
11 | return serialName?.value ?: property.name
12 | }
13 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/SerializableData.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseSerializer
4 | import io.github.jan.supabase.annotations.SupabaseInternal
5 |
6 | /**
7 | * An interface for data that can be serialized with [SupabaseSerializer]
8 | */
9 | interface SerializableData {
10 |
11 | /**
12 | * The serializer used to serialize this data
13 | */
14 | @SupabaseInternal
15 | val serializer: SupabaseSerializer
16 |
17 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/netModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.net.AuthApi
4 | import io.github.jan.supabase.common.net.AuthApiImpl
5 | import io.github.jan.supabase.common.net.MessageApi
6 | import io.github.jan.supabase.common.net.MessageApiImpl
7 | import org.koin.dsl.module
8 |
9 | val netModule = module {
10 | single { MessageApiImpl(get()) }
11 | single { AuthApiImpl(get()) }
12 | }
--------------------------------------------------------------------------------
/Postgrest/src/androidMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.SerialName
5 | import kotlin.reflect.KProperty1
6 | import kotlin.reflect.full.findAnnotation
7 |
8 | @SupabaseInternal
9 | actual fun getSerialName(property: KProperty1): String {
10 | val serialName = property.findAnnotation()
11 | return serialName?.value ?: property.name
12 | }
13 |
--------------------------------------------------------------------------------
/Auth/src/appleTest/kotlin/PlatformSetupTest.apple.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.setupPlatform
2 | import io.github.jan.supabase.auth.status.SessionStatus
3 | import kotlinx.coroutines.test.runTest
4 | import kotlin.test.assertIs
5 |
6 | class PlatformSetupTest {
7 |
8 | @kotlin.test.Test
9 | fun testPlatformSetupTestNoAutoLoad() = runTest {
10 | val auth = createMinimalAuthClient(autoSetup = false)
11 | auth.setupPlatform()
12 | assertIs(auth.sessionStatus.value)
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/Auth/src/jvmTest/kotlin/PlatformSetupTest.jvm.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.setupPlatform
2 | import io.github.jan.supabase.auth.status.SessionStatus
3 | import kotlinx.coroutines.test.runTest
4 | import kotlin.test.assertIs
5 |
6 | class PlatformSetupTest {
7 |
8 | @kotlin.test.Test
9 | fun testPlatformSetupTestNoAutoLoad() = runTest {
10 | val auth = createMinimalAuthClient(autoSetup = false)
11 | auth.setupPlatform()
12 | assertIs(auth.sessionStatus.value)
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/Auth/src/linuxTest/kotlin/PlatformSetupTest.linuxX64.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.setupPlatform
2 | import io.github.jan.supabase.auth.status.SessionStatus
3 | import kotlinx.coroutines.test.runTest
4 | import kotlin.test.assertIs
5 |
6 | class PlatformSetupTest {
7 |
8 | @kotlin.test.Test
9 | fun testPlatformSetupTestNoAutoLoad() = runTest {
10 | val auth = createMinimalAuthClient(autoSetup = false)
11 | auth.setupPlatform()
12 | assertIs(auth.sessionStatus.value)
13 | }
14 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
2 | pluginManagement {
3 | repositories {
4 | google()
5 | gradlePluginPortal()
6 | mavenCentral()
7 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
8 | maven("https://maven.hq.hydraulic.software")
9 | }
10 | }
11 |
12 | rootProject.name = "multiplatform-deeplinks"
13 |
14 | include(":desktop", ":common", ":android")
15 |
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/utils/FileSize.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | val Long.fileSize: String
4 | get() {
5 | val size = this.toDouble()
6 | return when {
7 | size < 1024 -> "${size.toLong()} B"
8 | size < 1024 * 1024 -> "${(size / 1024).toLong()} KB"
9 | size < 1024 * 1024 * 1024 -> "${(size / 1024 / 1024).toLong()} MB"
10 | else -> "${(size / 1024 / 1024 / 1024).toLong()} GB"
11 | }
12 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/SessionRequiredException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.exception
2 |
3 | import io.github.jan.supabase.StringMasking
4 | import io.ktor.http.Url
5 |
6 | /**
7 | * An exception thrown when trying to perform a request that requires a valid session while no user is logged in.
8 | * @param url The request url
9 | */
10 | class SessionRequiredException(url: String): Exception("You need to be logged in to perform this request\nURL: ${StringMasking.maskUrl(
11 | Url(url)
12 | )}")
13 |
--------------------------------------------------------------------------------
/Realtime/src/commonTest/kotlin/RealtimeTopicTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.realtime.RealtimeTopic
2 | import kotlin.test.Test
3 | import kotlin.test.assertEquals
4 |
5 | class RealtimeTopicTest {
6 |
7 | @Test
8 | fun testRealtimeTopic() {
9 | val channelId = "channelId"
10 | val topic = RealtimeTopic.withChannelId(channelId)
11 | assertEquals("realtime:channelId", topic)
12 | }
13 |
14 | @Test
15 | fun testRealtimePrefix() {
16 | assertEquals("realtime", RealtimeTopic.PREFIX)
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/logging/LogLevel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.logging
2 |
3 | /**
4 | * Represents a log level
5 | *
6 | */
7 | enum class LogLevel {
8 | /**
9 | * Debug log level
10 | */
11 | DEBUG,
12 |
13 | /**
14 | * Info log level
15 | */
16 | INFO,
17 |
18 | /**
19 | * Warning log level
20 | */
21 | WARNING,
22 | /**
23 | * Error log level
24 | */
25 | ERROR,
26 |
27 | /**
28 | * No log level
29 | */
30 | NONE,
31 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/CustomSerializationPlugin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseClientBuilder
4 | import io.github.jan.supabase.SupabaseSerializer
5 |
6 | /**
7 | * A plugin, which allows to customize the serialization
8 | */
9 | interface CustomSerializationPlugin {
10 |
11 | /**
12 | * The serializer used for this module. Defaults to [SupabaseClientBuilder.defaultSerializer], when null.
13 | */
14 | val serializer: SupabaseSerializer
15 |
16 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/AccessTokenProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * Optional function for using a third-party authentication system with
5 | * Supabase. The function should return an access token or ID token (JWT) by
6 | * obtaining it from the third-party auth client library. Note that this
7 | * function may be called concurrently and many times. Use memoization and
8 | * locking techniques if this is not supported by the client libraries.
9 | */
10 | typealias AccessTokenProvider = suspend () -> String?
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/CustomSerializationConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseClientBuilder
4 | import io.github.jan.supabase.SupabaseSerializer
5 |
6 | /**
7 | * A configuration for a plugin, which allows to customize the serialization
8 | */
9 | interface CustomSerializationConfig {
10 |
11 | /**
12 | * The serializer used for this module. Defaults to [SupabaseClientBuilder.defaultSerializer], when null.
13 | */
14 | var serializer: SupabaseSerializer?
15 |
16 | }
--------------------------------------------------------------------------------
/Supabase/src/mingwMain/kotlin/io/github/jan/supabase/PlatformTarget.mingw.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import platform.windows.DWORD
4 | import platform.windows.GetVersion
5 |
6 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
7 | name = "Windows",
8 | version = getOSVersion()
9 | )
10 |
11 | private fun getOSVersion(): String {
12 | val dwVersion: DWORD = GetVersion()
13 |
14 | val dwMajorVersion = dwVersion and 255u
15 | val dwMinorVersion = (dwVersion shr 8) and 255u
16 | return "$dwMajorVersion.$dwMinorVersion"
17 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.material3.Button
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 |
7 | @Composable
8 | actual fun AlertDialog(text: String, close: () -> Unit) {
9 | androidx.compose.material3.AlertDialog(
10 | text = { Text(text) },
11 | onDismissRequest = close,
12 | confirmButton = { Button(onClick = close) { Text("Ok") } }
13 | )
14 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonTest/kotlin/Utils.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.annotations.SupabaseInternal
2 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
3 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
4 |
5 | @SupabaseInternal
6 | inline fun postgrestRequest(propertyConversionMethod: PropertyConversionMethod = PropertyConversionMethod.CAMEL_CASE_TO_SNAKE_CASE, block: PostgrestRequestBuilder.() -> Unit): PostgrestRequestBuilder {
7 | val filter = PostgrestRequestBuilder(propertyConversionMethod)
8 | filter.block()
9 | return filter
10 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.material3.Button
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 |
7 | @Composable
8 | actual fun AlertDialog(text: String, close: () -> Unit) {
9 | androidx.compose.material3.AlertDialog(
10 | text = { Text(text) },
11 | onDismissRequest = close,
12 | confirmButton = { Button(onClick = close) { Text("Ok") } }
13 | )
14 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.material3.Button
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 |
7 | @Composable
8 | actual fun AlertDialog(text: String, close: () -> Unit) {
9 | androidx.compose.material3.AlertDialog(
10 | text = { Text(text) },
11 | onDismissRequest = close,
12 | confirmButton = { Button(onClick = close) { Text("Ok") } }
13 | )
14 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/filter/TextSearchType.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 | package io.github.jan.supabase.postgrest.query.filter
7 |
8 | /**
9 | * Used to search rows using a full text search. See [Postgrest](https://postgrest.org/en/stable/api.html#full-text-search) for more information
10 | */
11 | enum class TextSearchType(val identifier: String) {
12 | NONE(""),
13 | PLAINTO("pl"),
14 | PHRASETO("ph"),
15 | WEBSEARCH("w")
16 | }
--------------------------------------------------------------------------------
/Auth/src/androidUnitTest/kotlin/PlatformSetupTest.android.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.setupPlatform
2 | import io.github.jan.supabase.auth.status.SessionStatus
3 | import kotlinx.coroutines.test.runTest
4 | import kotlin.test.assertIs
5 |
6 | class PlatformSetupTest {
7 |
8 | @kotlin.test.Test
9 | fun testPlatformSetupTestNoAutoLoad() = runTest {
10 | val auth = createMinimalAuthClient(autoSetup = false) //Note: this does not test the lifecycle callbacks
11 | auth.setupPlatform()
12 | assertIs(auth.sessionStatus.value)
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import kotlinx.serialization.json.JsonObjectBuilder
4 | import kotlinx.serialization.json.put
5 |
6 | internal fun JsonObjectBuilder.putImageTransformation(transformation: ImageTransformation) {
7 | transformation.width?.let { put("width", it) }
8 | transformation.height?.let { put("height", it) }
9 | transformation.resize?.let { put("resize", it.name.lowercase()) }
10 | transformation.quality?.let { put("quality", it) }
11 | transformation.format?.let { put("format", it) }
12 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/iosMain/kotlin/io/github/jan/supabase/common/App.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.compose.ui.window.ComposeUIViewController
4 | import org.koin.core.component.KoinComponent
5 | import org.koin.core.component.inject
6 | import platform.UIKit.UIViewController
7 |
8 | class RootComponent : KoinComponent {
9 | private val viewModel: ChatViewModel by inject()
10 | fun getViewModel(): ChatViewModel = viewModel
11 | }
12 |
13 | fun AppIos(viewModel: ChatViewModel): UIViewController = ComposeUIViewController {
14 | App(viewModel = viewModel)
15 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // chatdemoios
4 | //
5 | // Created by Hieu Vu on 23/12/2023.
6 | //
7 |
8 | import SwiftUI
9 | import common
10 |
11 |
12 | struct ContentView: UIViewControllerRepresentable {
13 |
14 | let viewModel: ChatViewModel = RootComponent().getViewModel()
15 |
16 | func makeUIViewController(context: Context) -> UIViewController {
17 | return AppKt.AppIos(viewModel: viewModel)
18 | }
19 |
20 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Auth/src/iosMain/kotlin/io/github/jan/supabase/auth/providers/openUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import io.github.jan.supabase.auth.Auth
4 | import io.github.jan.supabase.logging.d
5 | import io.github.jan.supabase.logging.e
6 | import platform.Foundation.NSURL
7 | import platform.UIKit.UIApplication
8 |
9 | internal actual fun openUrl(url: NSURL) {
10 | UIApplication.sharedApplication.openURL(url, emptyMap()) {
11 | if(it) Auth.logger.d { "Successfully opened provider url in safari" } else Auth.logger.e { "Failed to open provider url in safari" }
12 | }
13 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/data/BroadcastApiBody.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.data
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonObject
6 |
7 | @Serializable
8 | internal data class BroadcastApiBody(
9 | val messages: List
10 | )
11 |
12 | @Serializable
13 | internal data class BroadcastApiMessage(
14 | val topic: String,
15 | val event: String,
16 | val payload: JsonObject,
17 | @SerialName("private")
18 | val isPrivate: Boolean
19 | )
20 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthSessionMissingException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.exception
2 |
3 | import io.ktor.client.statement.HttpResponse
4 |
5 | /**
6 | * Exception thrown when a session is not found.
7 | */
8 | class AuthSessionMissingException(response: HttpResponse): AuthRestException(
9 | errorCode = CODE,
10 | response = response,
11 | errorDescription = "Session not found. This can happen if the user was logged out or deleted."
12 | ) {
13 |
14 | internal companion object {
15 | const val CODE = "session_not_found"
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/Storage/src/androidMain/kotlin/io/github/jan/supabase/storage/Context.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | private var appContext: Context? = null
7 |
8 | internal class SupabaseInitializer : Initializer {
9 | override fun create(context: Context): Context = context.applicationContext.also { appContext = it }
10 |
11 | override fun dependencies(): List>> = emptyList()
12 |
13 | }
14 |
15 | internal fun applicationContext(): Context = appContext ?: error("Application context not initialized")
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/JsonUtils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import kotlinx.serialization.json.JsonObjectBuilder
4 | import kotlinx.serialization.json.put
5 | import kotlinx.serialization.json.putJsonObject
6 |
7 | internal fun JsonObjectBuilder.putCaptchaToken(token: String) {
8 | putJsonObject("gotrue_meta_security") {
9 | put("captcha_token", token)
10 | }
11 | }
12 |
13 | internal fun JsonObjectBuilder.putCodeChallenge(codeChallenge: String) {
14 | put("code_challenge", codeChallenge)
15 | put("code_challenge_method", PKCEConstants.CHALLENGE_METHOD)
16 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/xcuserdata/hieuvu.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | ShowSharedSchemesAutomaticallyEnabled
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx4096m
4 | kotlin.mpp.androidSourceSetLayoutVersion=2
5 | kotlin.native.ignoreDisabledTargets=true
6 | org.gradle.parallel=true
7 | kotlin.suppressGradlePluginWarnings=IncorrectCompileOnlyDependencyWarning
8 |
9 | org.jetbrains.compose.experimental.uikit.enabled=true
10 | org.jetbrains.compose.experimental.jscanvas.enabled=true
11 | org.jetbrains.compose.experimental.wasm.enabled=true
12 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
13 |
14 | supabase-version = 3.3.0-rc-1
15 | base-group = io.github.jan-tennert.supabase
16 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/desktopMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.res.loadSvgPainter
8 | import androidx.compose.ui.unit.Density
9 |
10 | @Composable
11 | actual fun QRCode(svgData: String, modifier: Modifier) {
12 | val painter = remember { loadSvgPainter(svgData.byteInputStream(), Density(1f)) }
13 | Image(painter, null, modifier)
14 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/UrlUtils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import io.ktor.http.URLBuilder
5 | import io.ktor.http.Url
6 |
7 | @SupabaseInternal
8 | inline fun buildUrl(baseUrl: String, init: URLBuilder.() -> Unit): String {
9 | val builder = URLBuilder(baseUrl)
10 | builder.init()
11 | return builder.buildString()
12 | }
13 |
14 | @SupabaseInternal
15 | inline fun buildUrl(baseUrl: Url, init: URLBuilder.() -> Unit): String {
16 | val builder = URLBuilder(baseUrl)
17 | builder.init()
18 | return builder.buildString()
19 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/SupabaseInitializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | private var appContext: Context? = null
7 |
8 | internal class SupabaseInitializer : Initializer {
9 | override fun create(context: Context): Context = context.applicationContext.also { appContext = it }
10 |
11 | override fun dependencies(): List>> = emptyList()
12 |
13 | }
14 |
15 | internal fun applicationContext(): Context = appContext ?: error("Application context not initialized")
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gradle" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 | reviewers:
13 | - "jan-tennert"
14 | assignees:
15 | - "jan-tennert"
16 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/MinimalConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | /**
4 | * Applies minimal configuration to the [AuthConfig]. This is useful for server side applications, where you don't need to store the session or code verifier.
5 | * @see AuthConfigDefaults
6 | */
7 | fun AuthConfigDefaults.minimalConfig() {
8 | this.alwaysAutoRefresh = false
9 | this.autoLoadFromStorage = false
10 | this.autoSaveToStorage = false
11 | this.sessionManager = MemorySessionManager()
12 | this.codeVerifierCache = MemoryCodeVerifierCache()
13 | this.enableLifecycleCallbacks = false
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/data/PostgresActionData.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.data
2 |
3 | import io.github.jan.supabase.realtime.Column
4 | import kotlinx.serialization.SerialName
5 | import kotlinx.serialization.Serializable
6 | import kotlinx.serialization.json.JsonObject
7 | import kotlin.time.Instant
8 |
9 | @Serializable
10 | internal data class PostgresActionData(
11 | val record: JsonObject? = null,
12 | @SerialName("old_record")
13 | val oldRecord: JsonObject? = null,
14 | val columns: List,
15 | @SerialName("commit_timestamp")
16 | val commitTimestamp: Instant
17 | )
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/SignOutScope.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | /**
4 | * Represents the scope of a sign-out action.
5 | *
6 | * The sign-out scope determines the scope of the sign-out action being performed.
7 | */
8 | enum class SignOutScope {
9 | /**
10 | * Sign-out action applies to all sessions across the entire system.
11 | */
12 | GLOBAL,
13 |
14 | /**
15 | * Sign-out action applies only to the current session.
16 | */
17 | LOCAL,
18 |
19 | /**
20 | * Sign-out action applies to other sessions, excluding the current session.
21 | */
22 | OTHERS
23 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/websocket/RealtimeWebsocketFactory.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.websocket
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | /**
6 | * Interface for creating a websocket connection to the Supabase Realtime service.
7 | */
8 | @OptIn(ExperimentalSubclassOptIn::class)
9 | @SubclassOptInRequired(SupabaseInternal::class)
10 | interface RealtimeWebsocketFactory {
11 |
12 | /**
13 | * Create a new websocket connection to the given URL.
14 | * @param url The URL to connect to.
15 | */
16 | suspend fun create(url: String): RealtimeWebsocket
17 |
18 | }
--------------------------------------------------------------------------------
/demos/android-login/build.gradle.kts:
--------------------------------------------------------------------------------
1 | group = "io.github.jan.supabase"
2 | version = "1.0-SNAPSHOT"
3 |
4 | plugins {
5 | alias(libs.plugins.kotlin.multiplatform) apply false
6 | alias(libs.plugins.kotlin.android) apply false
7 | alias(libs.plugins.kotlinx.plugin.serialization) apply false
8 | alias(libs.plugins.android.application) apply false
9 | alias(libs.plugins.android.library) apply false
10 | alias(libs.plugins.compose) apply false
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | mavenCentral()
17 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/websocket/KtorRealtimeWebsocketFactory.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.websocket
2 |
3 | import io.ktor.client.HttpClient
4 | import io.ktor.client.plugins.websocket.webSocketSession
5 |
6 | /**
7 | * Implementation of [RealtimeWebsocketFactory] using Ktor's [HttpClient].
8 | */
9 | class KtorRealtimeWebsocketFactory(
10 | private val httpClient: HttpClient,
11 | ): RealtimeWebsocketFactory {
12 |
13 | override suspend fun create(url: String): RealtimeWebsocket {
14 | val ws = httpClient.webSocketSession(url)
15 | return KtorRealtimeWebsocket(ws)
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.compose.plugin.get().pluginId)
4 | alias(libs.plugins.compose.compiler)
5 | alias(libs.plugins.kotlinx.plugin.serialization)
6 | }
7 |
8 | group = "io.github.jan.supabase"
9 | version = "1.0-SNAPSHOT"
10 |
11 |
12 | kotlin {
13 | js(IR) {
14 | browser()
15 | binaries.executable()
16 | }
17 | sourceSets {
18 | val jsMain by getting {
19 | dependencies {
20 | implementation(project(":sample:chat-demo-mpp:common"))
21 | }
22 | }
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthStringMasking.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.StringMasking
4 | import io.github.jan.supabase.auth.user.UserSession
5 |
6 | internal fun StringMasking.maskSession(value: UserSession): UserSession {
7 | return value.copy(
8 | accessToken = maskString(value.accessToken, showLength = true),
9 | refreshToken = maskString(value.refreshToken, showLength = true),
10 | providerRefreshToken = value.providerRefreshToken?.let { maskString(it, showLength = true) },
11 | providerToken = value.providerToken?.let { maskString(it, showLength = true) }
12 | )
13 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/build.gradle.kts:
--------------------------------------------------------------------------------
1 | group = "io.github.jan.supabase"
2 | version = "1.0-SNAPSHOT"
3 |
4 | allprojects {
5 | repositories {
6 | google()
7 | mavenCentral()
8 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
9 | mavenLocal()
10 | }
11 | }
12 |
13 | plugins {
14 | alias(libs.plugins.kotlin.multiplatform) apply false
15 | alias(libs.plugins.kotlin.android) apply false
16 | alias(libs.plugins.kotlinx.plugin.serialization) apply false
17 | alias(libs.plugins.android.application) apply false
18 | alias(libs.plugins.android.library) apply false
19 | alias(libs.plugins.compose) apply false
20 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/xcuserdata/hieuvu.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | chatdemoios.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 6581F14D2B36C0CF00BA34A9
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/supabaseModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.Auth
4 | import io.github.jan.supabase.auth.AuthConfig
5 | import io.github.jan.supabase.createSupabaseClient
6 | import org.koin.dsl.module
7 |
8 | expect fun AuthConfig.platformGoTrueConfig()
9 |
10 | val supabaseModule = module {
11 | single {
12 | createSupabaseClient(
13 | supabaseUrl = "YOUR_URL",
14 | supabaseKey = "YOUR_KEY"
15 | ) {
16 | install(Auth) {
17 | platformGoTrueConfig()
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Auth/src/macosMain/kotlin/io/github/jan/supabase/auth/providers/openUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import io.github.jan.supabase.auth.Auth
4 | import io.github.jan.supabase.logging.d
5 | import io.github.jan.supabase.logging.e
6 | import platform.AppKit.NSWorkspace
7 | import platform.AppKit.NSWorkspaceOpenConfiguration
8 | import platform.Foundation.NSURL
9 |
10 | internal actual fun openUrl(url: NSURL) {
11 | NSWorkspace.sharedWorkspace().openURL(url, NSWorkspaceOpenConfiguration()) { _, error ->
12 | if(error != null) Auth.logger.d { "Successfully opened provider url in safari" } else Auth.logger.e { "Failed to open provider url in safari" }
13 | }
14 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthDependentPluginConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import io.github.jan.supabase.annotations.SupabaseExperimental
5 | import io.github.jan.supabase.auth.user.UserSession
6 |
7 | /**
8 | * Configuration for plugins depending on the Auth plugin
9 | */
10 | interface AuthDependentPluginConfig {
11 |
12 | /**
13 | * Whether to require a valid [UserSession] in the [Auth] plugin to make any request with this plugin. The [SupabaseClient.supabaseKey] cannot be used as fallback.
14 | */
15 | @SupabaseExperimental
16 | var requireValidSession: Boolean
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/supabaseModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.createSupabaseClient
4 | import io.github.jan.supabase.gotrue.GoTrue
5 | import io.github.jan.supabase.gotrue.GoTrueConfig
6 | import org.koin.dsl.module
7 |
8 | expect fun GoTrueConfig.platformGoTrueConfig()
9 |
10 | val supabaseModule = module {
11 | single {
12 | createSupabaseClient(
13 | supabaseUrl = "YOUR_URL",
14 | supabaseKey = "YOUR_KEY"
15 | ) {
16 | install(GoTrue) {
17 | platformGoTrueConfig()
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/web/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.compose.plugin.get().pluginId)
3 | alias(libs.plugins.compose.compiler)
4 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
5 | alias(libs.plugins.kotlinx.plugin.serialization)
6 | }
7 |
8 | group = "io.github.jan.supabase"
9 | version = "1.0-SNAPSHOT"
10 |
11 |
12 | kotlin {
13 | applyDefaultHierarchyTemplate()
14 | js(IR) {
15 | browser()
16 | binaries.executable()
17 | }
18 | sourceSets {
19 | val jsMain by getting {
20 | dependencies {
21 | implementation(project(":sample:multi-factor-auth:common"))
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.compose.ui.ExperimentalComposeUiApi
4 | import io.github.jan.supabase.storage.resumable.ResumableClient
5 | import io.github.jan.supabase.storage.resumable.ResumableUpload
6 | import io.github.vinceglb.filekit.core.PlatformFile
7 | import kotlinx.coroutines.Deferred
8 |
9 | @OptIn(ExperimentalComposeUiApi::class)
10 | expect fun parseFileTreeFromURIs(paths: List): List
11 |
12 | expect fun parseFileTreeFromPath(path: String): List
13 |
14 | expect suspend fun ResumableClient.continuePreviousPlatformUploads(): List>
--------------------------------------------------------------------------------
/Auth/src/commonTest/kotlin/UrlUtilsTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.redirectTo
2 | import io.ktor.client.request.HttpRequestBuilder
3 | import io.ktor.client.request.url
4 | import kotlin.test.Test
5 | import kotlin.test.assertEquals
6 |
7 | class UrlUtilsTest {
8 |
9 | @Test
10 | fun testRedirectTo() {
11 | val url = "https://example.com/"
12 | val redirectTo = "https://redirect.com"
13 | val newUrl = HttpRequestBuilder().apply {
14 | url(url)
15 | redirectTo(redirectTo)
16 | }.url.toString()
17 | val expectedUrl = "https://example.com/?redirect_to=https%3A%2F%2Fredirect.com"
18 | assertEquals(expectedUrl, newUrl)
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthWeakPasswordException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.exception
2 |
3 | import io.ktor.client.statement.HttpResponse
4 |
5 | /**
6 | * Exception thrown on sign-up if the password is too weak
7 | * @param description The description of the exception.
8 | * @param reasons The reasons why the password is weak.
9 | */
10 | class AuthWeakPasswordException(
11 | description: String,
12 | response: HttpResponse,
13 | val reasons: List
14 | ) : AuthRestException(
15 | CODE,
16 | description,
17 | response
18 | ) {
19 |
20 | internal companion object {
21 | const val CODE = "weak_password"
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/SelectRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
4 | import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder
5 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
6 |
7 | /**
8 | * Request builder for [PostgrestQueryBuilder.select]
9 | */
10 | class SelectRequestBuilder(propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) {
11 |
12 | /**
13 | * If true, no body will be returned. Useful when using count.
14 | */
15 | var head: Boolean = false
16 |
17 | }
--------------------------------------------------------------------------------
/Auth/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/Utils.android.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("RedundantSuspendModifier")
2 | package io.github.jan.supabase.auth
3 |
4 | import android.net.Uri
5 | import io.github.jan.supabase.SupabaseClient
6 | import io.github.jan.supabase.auth.user.UserSession
7 |
8 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
9 | openUrl(Uri.parse(url), auth.config.defaultExternalAuthAction)
10 | }
11 |
12 | internal actual suspend fun Auth.startExternalAuth(
13 | redirectUrl: String?,
14 | getUrl: suspend (redirectTo: String?) -> String,
15 | onSessionSuccess: suspend (UserSession) -> Unit
16 | ) {
17 | config.urlLauncher.openUrl(supabaseClient, getUrl(redirectUrl))
18 | }
--------------------------------------------------------------------------------
/Storage/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/Uploads.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import io.github.jan.supabase.storage.resumable.Fingerprint
4 | import io.github.jan.supabase.storage.resumable.ResumableUploadState
5 | import io.github.vinceglb.filekit.core.PlatformFile
6 | import io.ktor.utils.io.ByteReadChannel
7 |
8 | sealed interface UploadState {
9 |
10 | val fingerprint: Fingerprint
11 |
12 | data class Loading(override val fingerprint: Fingerprint) : UploadState
13 | data class Loaded(override val fingerprint: Fingerprint, val state: ResumableUploadState) : UploadState
14 |
15 | }
16 |
17 | expect val PlatformFile.dataProducer: suspend (offset: Long) -> ByteReadChannel
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/executor/RequestExecutor.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.executor
2 |
3 | import io.github.jan.supabase.postgrest.Postgrest
4 | import io.github.jan.supabase.postgrest.request.PostgrestRequest
5 | import io.github.jan.supabase.postgrest.result.PostgrestResult
6 |
7 | /**
8 | * Request executor interface
9 | *
10 | */
11 | sealed interface RequestExecutor {
12 |
13 | /**
14 | * Execute given PostgrestRequest
15 | *
16 | * @param path [String]
17 | * @param request [PostgrestRequest]
18 | * @return [PostgrestResult]
19 | */
20 | suspend fun execute(postgrest: Postgrest, path: String, request: PostgrestRequest): PostgrestResult
21 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/SelectRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.ktor.http.Headers
5 | import io.ktor.http.HttpMethod
6 |
7 | @PublishedApi
8 | internal class SelectRequest(
9 | val head: Boolean = false,
10 | val count: Count? = null,
11 | override val urlParams: Map,
12 | override val schema: String,
13 | override val headers: Headers = Headers.Empty,
14 | ): PostgrestRequest {
15 |
16 | override val method = if (head) HttpMethod.Head else HttpMethod.Get
17 | override val prefer = if (count != null) listOf("count=${count.identifier}") else listOf()
18 |
19 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/desktop/src/jvmMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.Window
2 | import androidx.compose.ui.window.application
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.ChatViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | class RootComponent : KoinComponent {
10 |
11 | val viewModel: ChatViewModel by inject()
12 |
13 | }
14 |
15 | fun main() {
16 | initKoin()
17 | val root = RootComponent()
18 | application {
19 | Window(onCloseRequest = ::exitApplication, title = "Chat App") {
20 | App(root.viewModel)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/desktop/src/jvmMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.Window
2 | import androidx.compose.ui.window.application
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.AppViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | class RootComponent : KoinComponent {
10 |
11 | val viewModel: AppViewModel by inject()
12 |
13 | }
14 |
15 | fun main() {
16 | initKoin()
17 | val root = RootComponent()
18 | application {
19 | Window(onCloseRequest = ::exitApplication, title = "MFA App") {
20 | App(root.viewModel)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | io.github.jan.supabase.ios
7 | GIDClientID
8 | YOUR_IOS_CLIENT_ID
9 | CADisableMinimumFrameDurationOnPhone
10 |
11 | CFBundleURLTypes
12 |
13 |
14 | CFBundleTypeRole
15 | Editor
16 | CFBundleURLSchemes
17 |
18 | YOUR_REVERSED_IOS_CLIENT_ID
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/sample/file-upload/desktop/src/jvmMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.Window
2 | import androidx.compose.ui.window.application
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.UploadViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | class RootComponent : KoinComponent {
10 |
11 | val viewModel: UploadViewModel by inject()
12 |
13 | }
14 |
15 | fun main() {
16 | initKoin()
17 | val root = RootComponent()
18 | application {
19 | Window(onCloseRequest = ::exitApplication, title = "File Upload") {
20 | App(root.viewModel)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/collections/AtomicUtils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.collections
2 |
3 | import kotlin.concurrent.atomics.AtomicReference
4 |
5 | internal fun AtomicReference.updateIfChanged(callback: (T) -> T): Boolean {
6 | while(true) {
7 | val currentValue = load()
8 | val newValue = callback(currentValue)
9 | if(currentValue === newValue) return false
10 | if(compareAndSet(currentValue, newValue)) return true
11 | }
12 | }
13 |
14 | internal fun AtomicReference.update(callback: (T) -> T) {
15 | while(true) {
16 | val currentValue = load()
17 | val newValue = callback(currentValue)
18 | if(compareAndSet(currentValue, newValue)) return
19 | }
20 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/RpcRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.ktor.http.Headers
5 | import io.ktor.http.HttpMethod
6 | import kotlinx.serialization.json.JsonElement
7 |
8 | @PublishedApi
9 | internal class RpcRequest(
10 | override val method: HttpMethod,
11 | val count: Count? = null,
12 | override val urlParams: Map,
13 | override val body: JsonElement? = null,
14 | override val schema: String = "public",
15 | override val headers: Headers = Headers.Empty
16 | ) : PostgrestRequest {
17 |
18 | override val prefer = if (count != null) listOf("count=${count.identifier}") else listOf()
19 |
20 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.compose.plugin.get().pluginId)
5 | alias(libs.plugins.compose.compiler)
6 | id("com.android.application")
7 | id(libs.plugins.kotlin.android.get().pluginId)
8 | alias(libs.plugins.kotlinx.plugin.serialization)
9 | }
10 |
11 | group = "io.github.jan.supabase"
12 | version = "1.0-SNAPSHOT"
13 |
14 | dependencies {
15 | implementation(project(":sample:chat-demo-mpp:common"))
16 | implementation(libs.androidx.activity.compose)
17 | }
18 |
19 | android {
20 | configureApplicationAndroidTarget(JavaVersion.VERSION_11)
21 | }
22 |
23 | kotlin {
24 | compilerOptions {
25 | jvmTarget = JvmTarget.JVM_11
26 | }
27 | }
--------------------------------------------------------------------------------
/Auth/src/webMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import io.ktor.util.PlatformUtils.IS_BROWSER
5 |
6 | /**
7 | * The configuration for [Auth]
8 | */
9 | actual class AuthConfig: AuthConfigDefaults() {
10 |
11 | /**
12 | * Whether to disable automatic URL checking for PKCE codes, error codes, and session tokens.
13 | */
14 | var disableUrlChecking: Boolean = false
15 |
16 | /**
17 | * Interface to access browser properties like the current hash. By default, null on NodeJS. Can be changed for testing.
18 | */
19 | @SupabaseInternal
20 | var browserBridge: BrowserBridge? = if(IS_BROWSER) BrowserBridgeImpl() else null
21 |
22 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.compose.plugin.get().pluginId)
5 | alias(libs.plugins.compose.compiler)
6 | id("com.android.application")
7 | id(libs.plugins.kotlin.android.get().pluginId)
8 | alias(libs.plugins.kotlinx.plugin.serialization)
9 | }
10 |
11 | group = "io.github.jan.supabase"
12 | version = "1.0-SNAPSHOT"
13 |
14 | dependencies {
15 | implementation(libs.androidx.activity.compose)
16 | implementation(project(":sample:multi-factor-auth:common"))
17 | }
18 |
19 | android {
20 | configureApplicationAndroidTarget(JavaVersion.VERSION_11)
21 | }
22 |
23 | kotlin {
24 | compilerOptions {
25 | jvmTarget = JvmTarget.JVM_11
26 | }
27 | }
--------------------------------------------------------------------------------
/demos/android-login/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
43 |
44 | local.properties
45 |
46 | /wix311/
--------------------------------------------------------------------------------
/Functions/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Edge Functions Client"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | kotlin {
13 | defaultConfig()
14 | allTargets()
15 | sourceSets {
16 | commonMain {
17 | dependencies {
18 | addModules(SupabaseModule.AUTH, SupabaseModule.SUPABASE)
19 | }
20 | }
21 | commonTest {
22 | dependencies {
23 | implementation(project(":test-common"))
24 | implementation(libs.bundles.testing)
25 | }
26 | }
27 | }
28 | }
29 |
30 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/resumable/StreamContent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage.resumable
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import io.ktor.http.ContentType
5 | import io.ktor.http.content.OutgoingContent
6 | import io.ktor.utils.io.ByteWriteChannel
7 |
8 | @SupabaseInternal
9 | internal class StreamContent(
10 | size: Long,
11 | private val copyTo: suspend ByteWriteChannel.() -> Unit
12 | ) : OutgoingContent.WriteChannelContent() {
13 |
14 | override val contentLength: Long = size
15 | override val contentType: ContentType = ContentType.parse("application/offset+octet-stream")
16 |
17 | override suspend fun writeTo(channel: ByteWriteChannel) {
18 | copyTo(channel)
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/serializer/KotlinXSerializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.serializer
2 |
3 | import io.github.jan.supabase.SupabaseSerializer
4 | import kotlinx.serialization.json.Json
5 | import kotlinx.serialization.serializer
6 | import kotlin.reflect.KType
7 |
8 | /**
9 | * A [SupabaseSerializer] that uses kotlinx.serialization
10 | */
11 | class KotlinXSerializer(private val json: Json = Json) : SupabaseSerializer {
12 |
13 | override fun encode(type: KType, value: T): String = json.encodeToString(json.serializersModule.serializer(type), value)
14 |
15 | @Suppress("UNCHECKED_CAST")
16 | override fun decode(type: KType, value: String): T =
17 | json.decodeFromString(json.serializersModule.serializer(type), value) as T
18 |
19 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/web/src/jsMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.ExperimentalComposeUiApi
2 | import androidx.compose.ui.window.ComposeViewport
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.AppViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.jetbrains.skiko.wasm.onWasmReady
7 | import org.koin.core.component.KoinComponent
8 | import org.koin.core.component.inject
9 |
10 | class RootComponent : KoinComponent {
11 |
12 | val viewModel: AppViewModel by inject()
13 |
14 | }
15 |
16 | @OptIn(ExperimentalComposeUiApi::class)
17 | fun main() {
18 | initKoin()
19 | val root = RootComponent()
20 | onWasmReady {
21 | ComposeViewport("ComposeTarget") {
22 | App(root.viewModel)
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/StorageItem.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | /**
4 | * Represents a file in the storage bucket.
5 | * @param path The path of the file.
6 | * @param bucketId The id of the bucket.
7 | * @param authenticated Whether the file has to be accessed authenticated or not.
8 | */
9 | data class StorageItem(
10 | val path: String,
11 | val bucketId: String,
12 | val authenticated: Boolean
13 | )
14 |
15 | /**
16 | * Creates a [StorageItem] for an authenticated file.
17 | */
18 | fun authenticatedStorageItem(bucketId: String, path: String) = StorageItem(path, bucketId, true)
19 |
20 | /**
21 | * Creates a [StorageItem] for a public file.
22 | */
23 | fun publicStorageItem(bucketId: String, path: String) = StorageItem(path, bucketId, false)
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | desktop/output
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### IntelliJ IDEA ###
9 | .idea/modules.xml
10 | .idea/jarRepositories.xml
11 | .idea/compiler.xml
12 | .idea/libraries/
13 | *.iws
14 | *.iml
15 | *.ipr
16 | out/
17 | !**/src/main/**/out/
18 | !**/src/test/**/out/
19 |
20 | ### Eclipse ###
21 | .apt_generated
22 | .classpath
23 | .factorypath
24 | .project
25 | .settings
26 | .springBeans
27 | .sts4-cache
28 | bin/
29 | !**/src/main/**/bin/
30 | !**/src/test/**/bin/
31 |
32 | ### NetBeans ###
33 | /nbproject/private/
34 | /nbbuild/
35 | /dist/
36 | /nbdist/
37 | /.nb-gradle/
38 |
39 | ### VS Code ###
40 | .vscode/
41 |
42 | ### Mac OS ###
43 | .DS_Store
44 |
45 | local.properties
46 |
47 | /wix311/
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/mfa/MfaChallenge.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.mfa
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlin.time.Instant
6 |
7 | /**
8 | * A challenge to verify the user's identity.
9 | * @property id The id of the challenge.
10 | * @property factorType Factor Type which generated the challenge.
11 | */
12 | @Serializable
13 | data class MfaChallenge(val id: String, @SerialName("type") val factorType: String) {
14 |
15 | @SerialName("expires_at") private val expiresAtSeconds: Long = 0
16 |
17 | /**
18 | * Timestamp in UNIX seconds when this challenge will no longer be usable.
19 | */
20 | val expiresAt: Instant
21 | get() = Instant.fromEpochSeconds(expiresAtSeconds)
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/sample/file-upload/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.compose.plugin.get().pluginId)
5 | alias(libs.plugins.compose.compiler)
6 | id("com.android.application")
7 | id(libs.plugins.kotlin.android.get().pluginId)
8 | alias(libs.plugins.kotlinx.plugin.serialization)
9 | }
10 |
11 | group = "io.github.jan.supabase"
12 | version = "1.0-SNAPSHOT"
13 |
14 | dependencies {
15 | implementation(project(":sample:file-upload:common"))
16 | implementation(libs.androidx.activity.compose)
17 | implementation(libs.accompanist.permissions)
18 | }
19 |
20 | android {
21 | configureApplicationAndroidTarget(JavaVersion.VERSION_11)
22 | }
23 |
24 | kotlin {
25 | compilerOptions {
26 | jvmTarget = JvmTarget.JVM_11
27 | }
28 | }
--------------------------------------------------------------------------------
/test-common/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Common test module"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | defaultConfig()
15 | allTargets()
16 | sourceSets {
17 | commonMain {
18 | dependencies {
19 | addModules(SupabaseModule.SUPABASE)
20 | implementation(libs.bundles.testing)
21 | }
22 | }
23 | commonTest {
24 | dependencies {
25 | implementation(libs.bundles.testing)
26 | }
27 | }
28 | }
29 | }
30 |
31 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/Supabase/src/appleMain/kotlin/io/supabase/supabase/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.supabase.supabase
2 |
3 | import kotlinx.cinterop.ExperimentalForeignApi
4 | import kotlinx.cinterop.UnsafeNumber
5 | import kotlinx.cinterop.useContents
6 |
7 | @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
8 | internal fun getOSVersion(): String {
9 | val processInfo = platform.Foundation.NSProcessInfo.processInfo
10 | return processInfo.operatingSystemVersion.useContents {
11 | val majorVersion = this.majorVersion
12 | val minorVersion = this.minorVersion
13 | val patchVersion = this.patchVersion
14 | buildString {
15 | append(majorVersion)
16 | append(".")
17 | append(minorVersion)
18 | append(".")
19 | append(patchVersion)
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/parseFileTreeFromPath.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import io.github.jan.supabase.storage.resumable.ResumableClient
4 | import io.github.jan.supabase.storage.resumable.ResumableUpload
5 | import io.github.vinceglb.filekit.core.PlatformFile
6 | import kotlinx.coroutines.Deferred
7 |
8 | actual fun parseFileTreeFromPath(path: String): List {
9 | TODO("Not yet implemented")
10 | }
11 |
12 | actual fun parseFileTreeFromURIs(paths: List): List {
13 | TODO("Not yet implemented")
14 | }
15 |
16 | actual suspend fun ResumableClient.continuePreviousPlatformUploads(): List> = throw UnsupportedOperationException()
17 | //not supported as you loose access to the uri's file after the app is closed
--------------------------------------------------------------------------------
/Functions/src/commonMain/kotlin/io/github/jan/supabase/functions/FunctionRegion.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UndocumentedPublicProperty")
2 | package io.github.jan.supabase.functions
3 |
4 | /**
5 | * The region where the function is invoked.
6 | * @param value The value of the region
7 | */
8 | enum class FunctionRegion(val value: String) {
9 | ANY("any"),
10 | AP_NORTHEAST_1("ap-northeast-1"),
11 | AP_NORTHEAST_2("ap-northeast-2"),
12 | AP_SOUTH_1("ap-south-1"),
13 | AP_SOUTHEAST_1("ap-southeast-1"),
14 | AP_SOUTHEAST_2("ap-southeast-2"),
15 | CA_CENTRAL_1("ca-central-1"),
16 | EU_CENTRAL_1("eu-central-1"),
17 | EU_WEST_1("eu-west-1"),
18 | EU_WEST_2("eu-west-2"),
19 | EU_WEST_3("eu-west-3"),
20 | SA_EAST_1("sa-east-1"),
21 | US_EAST_1("us-east-1"),
22 | US_WEST_1("us-west-1"),
23 | US_WEST_2("us-west-2"),
24 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/RpcRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.Postgrest
4 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
5 | import io.github.jan.supabase.postgrest.RpcMethod
6 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
7 |
8 | /**
9 | * Request builder for [Postgrest.rpc]
10 | */
11 | class RpcRequestBuilder(defaultSchema: String, propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) {
12 |
13 | /**
14 | * The HTTP method to use. Default is POST
15 | */
16 | var method: RpcMethod = RpcMethod.POST
17 |
18 | /**
19 | * The database schema
20 | */
21 | var schema: String = defaultSchema
22 |
23 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/UrlLauncher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import io.github.jan.supabase.annotations.SupabaseExperimental
5 |
6 | /**
7 | * A [UrlLauncher] is used to open a URL in the system browser.
8 | */
9 | @SupabaseExperimental
10 | fun interface UrlLauncher {
11 |
12 | /**
13 | * Open the given URL in the system browser.
14 | * @param url The URL to open.
15 | */
16 | suspend fun openUrl(supabase: SupabaseClient, url: String)
17 |
18 | companion object {
19 |
20 | /**
21 | * Default implementation of [UrlLauncher] that opens the URL in the system browser.
22 | */
23 | val DEFAULT = UrlLauncher { supabase, url ->
24 | supabase.openExternalUrl(url)
25 | }
26 |
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/bom/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `java-platform`
3 | }
4 |
5 | description = "A Kotlin Multiplatform Supabase Framework"
6 |
7 | val bomProject = project
8 |
9 | val excludedModules = listOf("test-common")
10 |
11 | fun shouldIncludeInBom(candidateProject: Project) =
12 | excludedModules.all { !candidateProject.name.contains(it) } &&
13 | candidateProject.name != bomProject.name
14 |
15 | rootProject.subprojects.filter(::shouldIncludeInBom).forEach { bomProject.evaluationDependsOn(it.path) }
16 |
17 | dependencies {
18 | constraints {
19 | rootProject.subprojects.filter { project ->
20 | // Only declare dependencies on projects that will have publications
21 | shouldIncludeInBom(project) && project.tasks.findByName("publish")?.enabled == true
22 | }.forEach { api(project(it.path)) }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/serializers/Jackson/src/commonMain/kotlin/io/github/jan/supabase/serializer/JacksonSerializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.serializer
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper
4 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
5 | import io.github.jan.supabase.SupabaseSerializer
6 | import kotlin.reflect.KType
7 | import kotlin.reflect.javaType
8 |
9 | /**
10 | * A [SupabaseSerializer] that uses jackson-module-kotlin
11 | */
12 | class JacksonSerializer(private val mapper: ObjectMapper = jacksonObjectMapper()) : SupabaseSerializer {
13 |
14 | override fun encode(type: KType, value: T): String = mapper.writeValueAsString(value)
15 |
16 | @OptIn(ExperimentalStdlibApi::class)
17 | override fun decode(type: KType, value: String): T = mapper.readValue(value, mapper.constructType(type.javaType))
18 |
19 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/InsertRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
4 | import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder
5 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
6 |
7 | /**
8 | * Request builder for [PostgrestQueryBuilder.insert]
9 | */
10 | open class InsertRequestBuilder(propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) {
11 |
12 | /**
13 | * Make missing fields default to `null`.
14 | * Otherwise, use the default value for the column. This only applies when
15 | * inserting new rows, not when merging with existing rows under
16 | */
17 | var defaultToNull: Boolean = true
18 |
19 | }
--------------------------------------------------------------------------------
/Supabase/src/jvmTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import io.github.jan.supabase.getOSInformation
4 | import kotlin.test.Test
5 | import kotlin.test.assertEquals
6 |
7 | actual class PlatformTargetTest {
8 |
9 | @Test
10 | actual fun testPlatformTarget() {
11 | assertEquals(PlatformTarget.JVM, CurrentPlatformTarget, "The current platform target should be DESKTOP")
12 | }
13 |
14 | @Test
15 | fun testGetOSInformation() {
16 | System.setProperty("os.name", "Linux")
17 | System.setProperty("os.version", "5.4.0")
18 | val osInfo = getOSInformation()
19 | assertEquals("Linux", osInfo?.name, "OS name should be Linux")
20 | assertEquals("5.4.0", osInfo?.version, "OS version should be 5.4.0")
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build project
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'master'
7 |
8 | concurrency:
9 | group: ${{ github.workflow }}-${{ github.ref }}
10 | cancel-in-progress: true
11 |
12 | jobs:
13 | build:
14 | runs-on: macos-latest
15 | steps:
16 | - name: Checkout sources
17 | uses: actions/checkout@v4
18 | - name: Set up JDK 17
19 | uses: actions/setup-java@v4
20 | with:
21 | java-version: '17'
22 | distribution: 'temurin'
23 | - name: Setup Gradle
24 | uses: gradle/actions/setup-gradle@v4.0.1
25 | with:
26 | cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
27 | cache-read-only: false
28 | - name: Build supabase-kt
29 | run: ./gradlew -DLibrariesOnly=true assemble --stacktrace --configuration-cache --scan
30 |
--------------------------------------------------------------------------------
/Auth/src/desktopMain/kotlin/io/github/jan/supabase/auth/Utils.desktop.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.auth.server.createServer
4 | import io.github.jan.supabase.auth.user.UserSession
5 | import kotlinx.coroutines.Dispatchers
6 | import kotlinx.coroutines.IO
7 | import kotlinx.coroutines.withContext
8 |
9 | internal actual suspend fun Auth.startExternalAuth(
10 | redirectUrl: String?,
11 | getUrl: suspend (redirectTo: String?) -> String,
12 | onSessionSuccess: suspend (UserSession) -> Unit
13 | ) {
14 | withContext(Dispatchers.IO) {
15 | if(redirectUrl != null) {
16 | config.urlLauncher.openUrl(supabaseClient, getUrl(redirectUrl))
17 | return@withContext
18 | }
19 | createServer({
20 | getUrl(it)
21 | }, supabaseClient.auth, onSessionSuccess)
22 | }
23 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/DeleteRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.github.jan.supabase.postgrest.query.Returning
5 | import io.ktor.http.Headers
6 | import io.ktor.http.HttpMethod
7 |
8 | @PublishedApi
9 | internal class DeleteRequest(
10 | override val returning: Returning = Returning.Minimal,
11 | private val count: Count? = null,
12 | override val urlParams: Map,
13 | override val schema: String,
14 | override val headers: Headers = Headers.Empty,
15 | ) : PostgrestRequest {
16 |
17 | override val method = HttpMethod.Delete
18 | override val prefer = buildList {
19 | add("return=${returning.identifier}")
20 | if (count != null) add("count=${count.identifier}")
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/status/RefreshFailureCause.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.status
2 |
3 | import io.github.jan.supabase.exceptions.RestException
4 |
5 | /**
6 | * Represents the cause of a refresh error
7 | */
8 | //Note: Move this interface when removing the deprecated property from [SessionStatus.RefreshFailure]
9 | sealed interface RefreshFailureCause {
10 |
11 | /**
12 | * The refresh failed due to a network error
13 | * @param exception The exception that caused the error
14 | */
15 | data class NetworkError(val exception: Throwable) : RefreshFailureCause
16 |
17 | /**
18 | * The refresh failed due to an internal server error
19 | * @param exception The rest exception that caused the error
20 | */
21 | data class InternalServerError(val exception: RestException) : RefreshFailureCause
22 |
23 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/PostgrestRequest.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 |
7 | package io.github.jan.supabase.postgrest.request
8 |
9 | import io.github.jan.supabase.annotations.SupabaseInternal
10 | import io.github.jan.supabase.postgrest.query.Returning
11 | import io.ktor.http.Headers
12 | import io.ktor.http.HttpMethod
13 | import kotlinx.serialization.json.JsonElement
14 |
15 | @SupabaseInternal
16 | sealed interface PostgrestRequest {
17 |
18 | val body: JsonElement? get() = null
19 | val method: HttpMethod
20 | val urlParams: Map
21 | val headers: Headers get() = Headers.Empty
22 | val returning: Returning get() = Returning.Minimal
23 | val prefer: List
24 | val schema: String
25 |
26 | }
--------------------------------------------------------------------------------
/Postgrest/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Postgrest Client"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | defaultConfig()
15 | allTargets()
16 | sourceSets {
17 | commonMain {
18 | dependencies {
19 | addModules(SupabaseModule.AUTH)
20 | api(libs.kotlin.reflect)
21 | }
22 | }
23 | commonTest {
24 | dependencies {
25 | implementation(libs.bundles.testing)
26 | implementation(project(":test-common"))
27 | }
28 | }
29 | }
30 | }
31 |
32 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/executor/RestRequestExecutor.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.executor
2 |
3 | import io.github.jan.supabase.postgrest.Postgrest
4 | import io.github.jan.supabase.postgrest.PostgrestImpl
5 | import io.github.jan.supabase.postgrest.request.PostgrestRequest
6 | import io.github.jan.supabase.postgrest.result.PostgrestResult
7 |
8 | @PublishedApi
9 | internal data object RestRequestExecutor : RequestExecutor {
10 |
11 | override suspend fun execute(
12 | postgrest: Postgrest,
13 | path: String,
14 | request: PostgrestRequest
15 | ): PostgrestResult {
16 | val authenticatedSupabaseApi = (postgrest as PostgrestImpl).api
17 | return authenticatedSupabaseApi.request(path) {
18 | configurePostgrestRequest(request)
19 | }.asPostgrestResult(postgrest)
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/filter/FilterOperator.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 | package io.github.jan.supabase.postgrest.query.filter
7 |
8 | /**
9 | * Represents a single filter operation
10 | */
11 | enum class FilterOperator(val identifier: String) {
12 | EQ("eq"),
13 | NEQ("neq"),
14 | GT("gt"),
15 | GTE("gte"),
16 | LT("lt"),
17 | LTE("lte"),
18 | LIKE("like"),
19 | MATCH("match"),
20 | ILIKE("ilike"),
21 | IMATCH("imatch"),
22 | IS("is"),
23 | IN("in"),
24 | CS("cs"),
25 | CD("cd"),
26 | SL("sl"),
27 | SR("sr"),
28 | NXL("nxl"),
29 | NXR("nxr"),
30 | ADJ("adj"),
31 | OV("ov"),
32 | FTS("fts"),
33 | PLFTS("plfts"),
34 | PHFTS("phfts"),
35 | WFTS("wfts"),
36 | }
--------------------------------------------------------------------------------
/Auth/src/webMain/kotlin/io/github/jan/supabase/auth/BrowserBridge.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import org.w3c.dom.Window
5 | import kotlin.js.ExperimentalWasmJsInterop
6 |
7 | @SupabaseInternal
8 | interface BrowserBridge {
9 |
10 | val hash: String
11 | val href: String
12 |
13 | fun replaceCurrentUrl(newUrl: String)
14 |
15 | }
16 |
17 | internal class BrowserBridgeImpl(
18 | private val window: Window = kotlinx.browser.window
19 | ): BrowserBridge {
20 |
21 | override val hash: String
22 | get() = window.location.hash
23 |
24 | override val href: String
25 | get() = window.location.href
26 |
27 | @OptIn(ExperimentalWasmJsInterop::class)
28 | override fun replaceCurrentUrl(newUrl: String) {
29 | window.history.replaceState(null, window.document.title, newUrl)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/jsMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.foundation.Canvas
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
8 | import androidx.compose.ui.graphics.nativeCanvas
9 | import org.jetbrains.skia.Data
10 | import org.jetbrains.skia.svg.SVGDOM
11 |
12 | @Composable
13 | actual fun QRCode(svgData: String, modifier: Modifier) {
14 | val svgDom = remember { SVGDOM(data = Data.makeFromBytes(svgData.encodeToByteArray())) }
15 | Canvas(modifier = modifier) {
16 | svgDom.setContainerSize(size.width,size.height)
17 | drawIntoCanvas { canvas ->
18 | svgDom.render(canvas.nativeCanvas)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/exception/PostgrestRestException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.exception
2 |
3 | import io.github.jan.supabase.exceptions.RestException
4 | import io.ktor.client.statement.HttpResponse
5 | import kotlinx.serialization.json.JsonElement
6 |
7 | /**
8 | * Exception thrown when a Postgrest request fails
9 | * @param message The error message
10 | * @param hint A hint to the error
11 | * @param details Additional details about the error
12 | * @param code The error code
13 | * @param response The response that caused the exception
14 | */
15 | class PostgrestRestException(
16 | message: String,
17 | val hint: String?,
18 | val details: JsonElement?,
19 | val code: String?,
20 | response: HttpResponse
21 | ): RestException(message, """
22 | Code: $code
23 | Hint: $hint
24 | Details: $details
25 | """.trimIndent(), response)
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RCloseEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.logging.d
4 | import io.github.jan.supabase.realtime.Realtime
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 |
8 | /**
9 | * Event that handles the closing of a channel
10 | */
11 | data object RCloseEvent : RealtimeEvent {
12 |
13 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
14 | channel.realtime.removeChannel(channel)
15 | Realtime.logger.d { "Unsubscribed from channel ${message.topic}" }
16 | channel.updateStatus(RealtimeChannel.Status.UNSUBSCRIBED)
17 | }
18 |
19 | override fun appliesTo(message: RealtimeMessage): Boolean {
20 | return message.event == RealtimeChannel.CHANNEL_EVENT_CLOSE
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Template for feature request
3 | title: '[Feature request]: '
4 | labels: ["enhancement"]
5 | body:
6 | - type: checkboxes
7 | id: latest-version
8 | attributes:
9 | label: General Info
10 | options:
11 | - label: I installed the latest version of supabase-kt
12 | required: true
13 | - label: I checked for similar feature requests
14 | required: true
15 | - type: textarea
16 | id: feature-request
17 | attributes:
18 | label: Feature request
19 | description: Please describe what you think should be added to Supabase Kt
20 | validations:
21 | required: true
22 | - type: textarea
23 | id: usecase
24 | attributes:
25 | label: Usecase
26 | description: 'Please provide an use case for your feature request'
27 | validations:
28 | required: false
29 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RPresenceStateEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.decodeIfNotEmptyOrDefault
4 | import io.github.jan.supabase.realtime.Presence
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 |
8 | /**
9 | * Event that handles the presence state event
10 | */
11 | data object RPresenceStateEvent : RealtimeEvent {
12 |
13 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
14 | val joins = message.payload.decodeIfNotEmptyOrDefault(mapOf())
15 | channel.callbackManager.triggerPresenceDiff(joins, mapOf())
16 | }
17 |
18 | override fun appliesTo(message: RealtimeMessage): Boolean {
19 | return message.event == RealtimeChannel.CHANNEL_EVENT_PRESENCE_STATE
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import io.github.jan.supabase.auth.Auth
4 |
5 | /**
6 | * Configuration for external authentication providers like Google, Twitter, etc.
7 | */
8 | expect class ExternalAuthConfig(): ExternalAuthConfigDefaults
9 |
10 | /**
11 | * The default values for [ExternalAuthConfig]
12 | */
13 | open class ExternalAuthConfigDefaults {
14 |
15 | /**
16 | * The scopes to request from the external provider
17 | */
18 | val scopes = mutableListOf()
19 |
20 | /**
21 | * Additional query parameters to send to the external provider
22 | */
23 | val queryParams = mutableMapOf()
24 |
25 | /**
26 | * Automatically open the URL in the browser. Only applies to [Auth.linkIdentity].
27 | */
28 | var automaticallyOpenUrl: Boolean = true
29 |
30 | }
--------------------------------------------------------------------------------
/Auth/src/commonTest/kotlin/CodeVerifierCacheTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.MemoryCodeVerifierCache
2 | import kotlinx.coroutines.test.runTest
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 | import kotlin.test.assertNull
6 |
7 | class CodeVerifierCacheTest {
8 |
9 | @Test
10 | fun testMemoryCodeVerifierCache() {
11 | runTest {
12 | val codeVerifier = "codeVerifier"
13 | val codeVerifierCache = MemoryCodeVerifierCache(codeVerifier)
14 | assertEquals(codeVerifier, codeVerifierCache.loadCodeVerifier())
15 | val newCodeVerifier = "newCodeVerifier"
16 | codeVerifierCache.saveCodeVerifier(newCodeVerifier)
17 | assertEquals(newCodeVerifier, codeVerifierCache.loadCodeVerifier())
18 | codeVerifierCache.deleteCodeVerifier()
19 | assertNull(codeVerifierCache.loadCodeVerifier())
20 | }
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/android/src/main/java/io/github/jan/supabase/android/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.material3.MaterialTheme
7 | import io.github.jan.supabase.auth.handleDeeplinks
8 | import io.github.jan.supabase.common.App
9 | import io.github.jan.supabase.common.ChatViewModel
10 | import org.koin.android.ext.android.inject
11 |
12 | class MainActivity : ComponentActivity() {
13 |
14 | private val viewModel: ChatViewModel by inject()
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | viewModel.supabaseClient.handleDeeplinks(intent)
19 | setContent {
20 | MaterialTheme {
21 | App(viewModel)
22 | }
23 | }
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/android/src/main/java/io/github/jan/supabase/android/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.material3.MaterialTheme
7 | import io.github.jan.supabase.auth.handleDeeplinks
8 | import io.github.jan.supabase.common.App
9 | import io.github.jan.supabase.common.AppViewModel
10 | import org.koin.android.ext.android.inject
11 |
12 | class MainActivity : ComponentActivity() {
13 |
14 | private val viewModel: AppViewModel by inject()
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | viewModel.supabaseClient.handleDeeplinks(intent)
19 | setContent {
20 | MaterialTheme {
21 | App(viewModel)
22 | }
23 | }
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/UpsertRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
4 | import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder
5 |
6 | /**
7 | * Request builder for [PostgrestQueryBuilder.upsert]
8 | */
9 | class UpsertRequestBuilder(propertyConversionMethod: PropertyConversionMethod): InsertRequestBuilder(propertyConversionMethod) {
10 |
11 | /**
12 | * Comma-separated UNIQUE column(s) to specify how
13 | * duplicate rows are determined. Two rows are duplicates if all the
14 | * `onConflict` columns are equal.
15 | */
16 | var onConflict: String? = null
17 |
18 | /**
19 | * If `true`, duplicate rows are ignored. If `false`, duplicate rows are merged with existing rows.
20 | */
21 | var ignoreDuplicates: Boolean = false
22 |
23 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/desktop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
5 | id(libs.plugins.compose.plugin.get().pluginId)
6 | alias(libs.plugins.compose.compiler)
7 | alias(libs.plugins.kotlinx.plugin.serialization)
8 | }
9 |
10 | group = "io.github.jan.supabase"
11 | version = "1.0-SNAPSHOT"
12 |
13 |
14 | kotlin {
15 | jvmToolchain(11)
16 | jvm {
17 | compilerOptions {
18 | jvmTarget = JvmTarget.JVM_11
19 | }
20 | }
21 | sourceSets {
22 | val jvmMain by getting {
23 | dependencies {
24 | implementation(project(":sample:chat-demo-mpp:common"))
25 | implementation(compose.desktop.currentOs)
26 | }
27 | }
28 | val jvmTest by getting
29 | }
30 | }
31 |
32 | compose.desktop.configureComposeDesktop("chat-demo-mpp")
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.remember
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.platform.LocalContext
7 | import coil.ImageLoader
8 | import coil.compose.AsyncImage
9 | import coil.decode.SvgDecoder
10 | import java.nio.ByteBuffer
11 |
12 | @Composable
13 | actual fun QRCode(svgData: String, modifier: Modifier) {
14 | val context = LocalContext.current
15 | val imageLoader = remember {
16 | ImageLoader.Builder(context)
17 | .components {
18 | add(SvgDecoder.Factory())
19 | }
20 | .build()
21 | }
22 | AsyncImage(model = ByteBuffer.wrap(svgData.toByteArray()), imageLoader = imageLoader, modifier = modifier, contentDescription = null)
23 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/desktop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.compose.plugin.get().pluginId)
5 | alias(libs.plugins.compose.compiler)
6 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
7 | alias(libs.plugins.kotlinx.plugin.serialization)
8 | }
9 |
10 | group = "io.github.jan.supabase"
11 | version = "1.0-SNAPSHOT"
12 |
13 |
14 | kotlin {
15 | jvmToolchain(11)
16 | jvm {
17 | compilerOptions {
18 | jvmTarget = JvmTarget.JVM_11
19 | }
20 | }
21 | sourceSets {
22 | val jvmMain by getting {
23 | dependencies {
24 | implementation(project(":sample:multi-factor-auth:common"))
25 | implementation(compose.desktop.currentOs)
26 | }
27 | }
28 | val jvmTest by getting
29 | }
30 | }
31 |
32 | compose.desktop.configureComposeDesktop("multi-factor-auth")
--------------------------------------------------------------------------------
/serializers/Jackson/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Jackson Serializer"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | defaultConfig()
15 | configuredAndroidTarget()
16 | configuredJvmTarget()
17 | sourceSets {
18 | commonMain {
19 | dependencies {
20 | addModules(SupabaseModule.SUPABASE)
21 | api(libs.bundles.jackson)
22 | }
23 | }
24 | commonTest {
25 | dependencies {
26 | implementation(libs.bundles.testing)
27 | implementation(project(":test-common"))
28 | }
29 | }
30 | }
31 | }
32 |
33 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/SupabaseClientConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.github.jan.supabase.logging.LogLevel
4 | import io.ktor.client.engine.HttpClientEngine
5 | import kotlinx.coroutines.CoroutineDispatcher
6 | import kotlin.time.Duration
7 |
8 | data class SupabaseClientConfig(
9 | val supabaseUrl: String,
10 | val supabaseKey: String,
11 | val defaultLogLevel: LogLevel,
12 | val networkConfig: SupabaseNetworkConfig,
13 | val defaultSerializer: SupabaseSerializer,
14 | val coroutineDispatcher: CoroutineDispatcher,
15 | val accessToken: AccessTokenProvider?,
16 | val plugins: Map,
17 | val osInformation: OSInformation?
18 | )
19 |
20 | data class SupabaseNetworkConfig(
21 | val useHTTPS: Boolean,
22 | val httpEngine: HttpClientEngine?,
23 | val httpConfigOverrides: List,
24 | val requestTimeout: Duration
25 | )
26 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/user/Identity.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UndocumentedPublicClass", "UndocumentedPublicFunction", "UndocumentedPublicProperty")
2 | package io.github.jan.supabase.auth.user
3 |
4 |
5 | import kotlinx.serialization.SerialName
6 | import kotlinx.serialization.Serializable
7 | import kotlinx.serialization.json.JsonObject
8 |
9 | @Serializable
10 | data class Identity(
11 | @SerialName("id")
12 | val id: String,
13 | @SerialName("identity_data")
14 | val identityData: JsonObject,
15 | @SerialName("identity_id")
16 | val identityId: String? = null,
17 | @SerialName("last_sign_in_at")
18 | val lastSignInAt: String? = null,
19 | @SerialName("updated_at")
20 | val updatedAt: String? = null,
21 | @SerialName("created_at")
22 | val createdAt: String? = null,
23 | @SerialName("provider")
24 | val provider: String,
25 | @SerialName("user_id")
26 | val userId: String
27 | )
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/UpdateRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.github.jan.supabase.postgrest.query.Returning
5 | import io.ktor.http.Headers
6 | import io.ktor.http.HttpMethod
7 | import kotlinx.serialization.json.JsonElement
8 |
9 | @PublishedApi
10 | internal class UpdateRequest(
11 | override val returning: Returning = Returning.Minimal,
12 | private val count: Count? = null,
13 | override val urlParams: Map,
14 | override val body: JsonElement,
15 | override val schema: String,
16 | override val headers: Headers = Headers.Empty,
17 | ) : PostgrestRequest {
18 |
19 | override val method = HttpMethod.Patch
20 | override val prefer = buildList {
21 | add("return=${returning.identifier}")
22 | if (count != null) add("count=${count.identifier}")
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/RealtimeCallback.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.json.JsonObject
5 |
6 | @SupabaseInternal
7 | sealed interface RealtimeCallback {
8 |
9 | val callback: (T) -> Unit
10 | val id: Int
11 |
12 | class PostgresCallback(
13 | override val callback: (PostgresAction) -> Unit,
14 | val filter: PostgresJoinConfig,
15 | override val id: Int
16 | ): RealtimeCallback
17 |
18 | class BroadcastCallback(
19 | override val callback: (JsonObject) -> Unit,
20 | val event: String,
21 | override val id: Int
22 | ): RealtimeCallback
23 |
24 | class PresenceCallback(
25 | override val callback: (PresenceAction) -> Unit,
26 | override val id: Int
27 | ): RealtimeCallback
28 |
29 | }
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/DownloadOptionBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import io.github.jan.supabase.network.HttpRequestOverride
4 |
5 | /**
6 | * Builder for downloading files with additional options
7 | */
8 | class DownloadOptionBuilder(
9 | internal var transform: ImageTransformation.() -> Unit = {},
10 | internal val httpRequestOverrides: MutableList = mutableListOf()
11 | ) {
12 |
13 | /**
14 | * Transforms the image before downloading
15 | * @param transform The transformation to apply
16 | */
17 | fun transform(transform: ImageTransformation.() -> Unit) {
18 | this.transform = transform
19 | }
20 |
21 | /**
22 | * Overrides the HTTP request
23 | * @param override The override to apply
24 | */
25 | fun httpOverride(override: HttpRequestOverride) {
26 | httpRequestOverrides.add(override)
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/src/jsMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 | import androidx.compose.ui.ExperimentalComposeUiApi
3 | import androidx.compose.ui.window.ComposeViewport
4 | import io.github.jan.supabase.common.App
5 | import io.github.jan.supabase.common.ChatViewModel
6 | import io.github.jan.supabase.common.di.initKoin
7 | import org.jetbrains.skiko.wasm.onWasmReady
8 | import org.koin.core.component.KoinComponent
9 | import org.koin.core.component.inject
10 |
11 | class RootComponent : KoinComponent {
12 |
13 | val viewModel: ChatViewModel by inject()
14 |
15 | }
16 |
17 | @OptIn(ExperimentalComposeUiApi::class)
18 | fun main() {
19 | initKoin()
20 | val root = RootComponent()
21 | onWasmReady {
22 | ComposeViewport("ComposeTarget") {
23 | App(root.viewModel)
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/serializers/Moshi/src/commonTest/kotlin/MoshiSerializerTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.encode
2 | import io.github.jan.supabase.serializer.MoshiSerializer
3 | import io.github.jan.supabase.testing.createMockedSupabaseClient
4 | import org.junit.Test
5 | import kotlin.reflect.typeOf
6 | import kotlin.test.assertEquals
7 |
8 | class MoshiSerializerTest {
9 |
10 | @Test
11 | fun testMoshiSerializer() {
12 | val serializer = MoshiSerializer()
13 | val supabaseClient = createMockedSupabaseClient(
14 | configuration = {
15 | defaultSerializer = serializer
16 | }
17 | )
18 | assertEquals(serializer, supabaseClient.defaultSerializer)
19 | val value = mapOf("key" to "value")
20 | val encoded = serializer.encode(value)
21 | val decoded = serializer.decode