Code Monkey home page Code Monkey logo

supabase-kt's Introduction

supabase-kt

A Kotlin Multiplatform Client for Supabase.

For information about supported Kotlin targets, see the corresponding module README.

Migrating from version 1.4.X to 2.0.0

Note: WASM build available: 2.2.3-wasm0

Kotlin https://img.shields.io/badge/ktor-2.3.10-blue slack

Links

Documentation

Getting started with Android and Supabase [Video]

Quickstart

Tutorial: Build a Product Management Android App with Jetpack Compose

Dokka documentation for the latest version

Troubleshooting

Installation

Add one ore more modules to your project

Available modules: gotrue-kt, postgrest-kt, functions-kt, storage-kt, realtime-kt, apollo-graphql, compose-auth, compose-auth-ui, coil-integration, imageloader-integration

dependencies {
    implementation("io.github.jan-tennert.supabase:[module]:VERSION")
}

If you use multiple modules, you can use the bom dependency to get the correct versions for all modules:

implementation(platform("io.github.jan-tennert.supabase:bom:VERSION"))
implementation("io.github.jan-tennert.supabase:[module]")

Add a Ktor Client Engine to each of your Kotlin targets

You can find a list of available engines here. If you plan to use the Realtime dependency, make sure to check if the engine supports WebSockets. See the Ktor docs for more information.

implementation("io.ktor:ktor-client-[engine]:VERSION")
Multiplatform Example

For targets: jvm, android, js, ios

val commonMain by getting {
    dependencies {
        //supabase modules
    }
}
val jvmMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-cio:KTOR_VERSION")
    }
}
val androidMain by getting {
    dependsOn(jvmMain)
}
val jsMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-js:KTOR_VERSION")
    }
}
val iosMain by getting {
    dependencies {
        implementation("io.ktor:ktor-client-darwin:KTOR_VERSION")
    }
}

Note: It is recommended to use the same Ktor version as supabase-kt:

https://img.shields.io/badge/ktor-2.3.10-blue

Main Modules

Plugins

Apollo GraphQL integration - Creates an Apollo GraphQL Client for interacting with the Supabase API.

Compose Auth - Provides easy Native Google & Apple Auth for Compose Multiplatform targets.

Compose Auth UI - Provides UI Components for Compose Multiplatform.

Coil Integration - Provides a Coil Integration for displaying images stored in Supabase Storage.

Compose-ImageLoader Integration - Provides a Compose ImageLoader Integration for displaying images stored in Supabase Storage.

Demos

Need help?

Videos

Contribution

How to contribute

  1. Fork the repository
  2. Create a branch
  3. Make your changes
  4. Submit a pull request with your new branch

Credits

supabase-kt's People

Contributors

brezinajn avatar dancing-koala avatar dependabot[bot] avatar dshukertjr avatar ferhatwi avatar hieuwu avatar iruizmar avatar jan-tennert avatar jollygreenegiant avatar kiwicopple avatar mohamedrejeb avatar ramirond avatar shubhamsinghshubham777 avatar softwaresale avatar temk0 avatar vinceglb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

supabase-kt's Issues

[Bug]: Impossible to get a list of files where there are folders

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

I'm trying to get a list of files in a folder, but because the folder has a null id, the resulting json cannot be serialized successfully

    val items: List<BucketItem> = storage["main"].list("Folders").onEach {
        println(it.name)
    }

Dashboard:
image

Postman:
image

But the BucketApi class requires a non-null id

@Serializable
data class BucketItem(
    val name: String,
    val id: String,
    @SerialName("updated_at")
    val updatedAt: Instant,
    @SerialName("created_at")
    val createdAt: Instant,
    @SerialName("last_accessed_at")
    val lastAccessedAt: Instant,
    val metadata: JsonObject
)

Platform(s)

Desktop

Relevant log output

Unexpected JSON token at offset 25: Expected string literal but 'null' literal was found at path: $[0].id
Use 'coerceInputValues = true' in 'Json {}` builder to coerce nulls to default values.
JSON input: [{"name":"Folder 1","id":null,"updated_at":null,"create.....
io.ktor.serialization.JsonConvertException: Unexpected JSON token at offset 25: Expected string literal but 'null' literal was found at path: $[0].id
Use 'coerceInputValues = true' in 'Json {}` builder to coerce nulls to default values.
JSON input: [{"name":"Folder 1","id":null,"updated_at":null,"create.....
	(Coroutine boundary)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:138)
	at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:88)
	at io.github.jan.supabase.storage.BucketApiImpl.list(BucketApi.kt:312)
	at com.studiversity.feature.course.submission.SubmissionRoutingKtTest$testAttachments$1.invokeSuspend(SubmissionRoutingKtTest.kt:35)
Caused by: io.ktor.serialization.JsonConvertException: Unexpected JSON token at offset 25: Expected string literal but 'null' literal was found at path: $[0].id
Use 'coerceInputValues = true' in 'Json {}` builder to coerce nulls to default values.
JSON input: [{"name":"Folder 1","id":null,"updated_at":null,"create.....
	(Coroutine boundary)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:138)
Caused by: io.ktor.serialization.JsonConvertException: Unexpected JSON token at offset 25: Expected string literal but 'null' literal was found at path: $[0].id
Use 'coerceInputValues = true' in 'Json {}` builder to coerce nulls to default values.
JSON input: [{"name":"Folder 1","id":null,"updated_at":null,"create.....
	at app//io.ktor.serialization.kotlinx.KotlinxSerializationConverter.deserialize(KotlinxSerializationConverter.kt:79)
	at app//io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1$2.emit(Emitters.kt:224)
	at app//kotlinx.coroutines.flow.FlowKt__BuildersKt$asFlow$$inlined$unsafeFlow$3.collect(SafeCollector.common.kt:115)
	at app//io.ktor.serialization.ContentConverterKt$deserialize$$inlined$map$1.collect(SafeCollector.common.kt:113)
	at app//kotlinx.coroutines.flow.FlowKt__ReduceKt.firstOrNull(Reduce.kt:243)
	at app//kotlinx.coroutines.flow.FlowKt.firstOrNull(Unknown Source)
	at app//io.ktor.serialization.ContentConverterKt.deserialize(ContentConverter.kt:128)
	at app//io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertResponse$ktor_client_content_negotiation(ContentNegotiation.kt:185)
	at app//io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invokeSuspend(ContentNegotiation.kt:210)
	at app//io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(ContentNegotiation.kt)
	at app//io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$2.invoke(ContentNegotiation.kt)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at app//io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:177)
	at app//io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
	at app//io.ktor.client.HttpClient$4.invoke(HttpClient.kt)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88)
	at app//io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:138)
	at app//io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(HttpCallValidator.kt)
	at app//io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invoke(HttpCallValidator.kt)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at app//io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
	at app//io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at app//io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:88)
	at app//io.github.jan.supabase.storage.BucketApiImpl.list(BucketApi.kt:396)
	at app//io.github.jan.supabase.storage.BucketApiImpl$list$1.invokeSuspend(BucketApi.kt)
	(Coroutine boundary)
	at io.ktor.client.HttpClient$4.invokeSuspend(HttpClient.kt:177)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$2.invokeSuspend(HttpCallValidator.kt:138)
	at io.ktor.client.call.HttpClientCall.bodyNullable(HttpClientCall.kt:88)
	at io.github.jan.supabase.storage.BucketApiImpl.list(BucketApi.kt:312)

[Bug]: 0.2.0 seemingly broke realtime observing

General Info

  • I installed the latest version of SupaCompose
  • I checked for similar bug report

What happened? (include your code)

Client application does not get notified about realtime updates.

realtime.connect()

val channel = realtime.createChannel("#test"){}

val flow = channel.postgresChangeFlow<PostgresAction> {
    schema = "public"
    table = "news"
}

channel.join()

flow.collectLatest {
    println(it)
}

Seems like RealtimeChannelImpl::onMessage function is not getting any messages for realtime updates.

Platform(s)

Android

Relevant log output

D/RealtimeChannelImpl$join: Joining channel realtime:#test
D/RealtimeImpl$onMessage: Received event phx_reply for channel realtime:#test
D/RealtimeImpl$onMessage: Received event presence_state for channel realtime:#test
W/ezinajn.stalke: Verification of java.lang.Object io.github.jan.supacompose.realtime.RealtimeChannelKt$postgresChangeFlow$1.invokeSuspend(java.lang.Object) took 312.585ms (275.12 bytecodes/s) (3424B approximate peak alloc)
D/RealtimeImpl$onMessage: Received event system for channel realtime:#test
D/RealtimeChannelImpl$onMessage: Joined channel realtime:#test
D/RealtimeImpl$sendHeartbeat: Sending heartbeat
I/RealtimeImpl$onMessage: Heartbeat received
D/RealtimeImpl$sendHeartbeat: Sending heartbeat
I/RealtimeImpl$onMessage: Heartbeat received
...

[Question]: How to use custom kotlinx.serialization Json?

What is your question?

projects table

[
  {
    "id": 1,
    "created_at": "2023-01-25T05:49:08.596679+00:00",
    "name": "MyProject1",
    "startOn": "2023-01-25"
  }
]

Project data class

@Serializable
data class Project(
  val id: Int,
  @Contextual @SerialName("created_at") val createdAt: LocalDateTime,
  val name: String,
  @Contextual val startOn: LocalDate
)

Serializer

object LocalDateSerializer : KSerializer<LocalDate> {
  private val formatter = DateTimeFormatter.ISO_DATE

  override val descriptor: SerialDescriptor
    get() = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: LocalDate) {
    encoder.encodeString(value.format(formatter))
  }

  override fun deserialize(decoder: Decoder): LocalDate {
    return LocalDate.parse(decoder.decodeString(), formatter)
  }
}
object LocalDateTimeSerializer : KSerializer<LocalDateTime> {
  private val formatter = DateTimeFormatter.ISO_DATE_TIME

  override val descriptor: SerialDescriptor
    get() = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)

  override fun serialize(encoder: Encoder, value: LocalDateTime) {
    encoder.encodeString(value.format(formatter))
  }

  override fun deserialize(decoder: Decoder): LocalDateTime {
    return LocalDateTime.parse(decoder.decodeString(), formatter)
  }
}

I use kotlinx.serialization like this.

val client = createSupabaseClient(
  supabaseUrl = "https://project-url.supabase.co",
  supabaseKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
) {
  install(Postgrest) {
    Json {
      ignoreUnknownKeys = true
      coerceInputValues = true
      encodeDefaults = true
      isLenient = true

      serializersModule += SerializersModule {
        contextual(LocalDateTimeSerializer)
        contextual(LocalDateSerializer)
      }
    }
  }
}

GlobalScope.launch {
  val result = client.postgrest.from("projects").select().decodeList<Project>()
}

error

kotlinx.datetime.DateTimeFormatException: java.time.format.DateTimeParseException: Text '2023-01-25T05:49:08.596679+00:00' could not be parsed, unparsed text found at index 26

How to use custom kotlinx.serialization Json?

[Bug]: Could not get realtime data update.

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

Trying to get real-time updates, added the below code.

  • Tried to update the record in the database....but no update on the app.

Am I doing something wrong?
On making changes in datatbase recrod manually, I should be able to get updated data on app right?
here
changeFlow.collect {
Log.e("supadata_optionCalled", "notification: " + it.decodeRecord())
}

Platform(s)

Android

Relevant log output

val key ="KEY"
    val supabaseClient = createSupabaseClient(
        supabaseUrl = "https://MY_URL.supabase.co/realtime/v1",
        supabaseKey = key
    ) {
        install(Realtime)
    }

val realtime = standaloneSupabaseModule(
            Realtime,
            url = "https://MY_URL.supabase.co/realtime/v1",
            apiKey = key
        )
        Log.e("supadata_optionCalled", "realtimeStatus: " + realtime.status)

        GlobalScope.launch {
            val channel = supabaseClient.realtime.createChannel("clips") {
                presence {
                    //presence options
                    Log.e("supadata_optionCalled", "present")
                }
                broadcast {
                    //broadcast options
                    Log.e("supadata_optionCalled", "broadcast")
                }
            }
            channel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
                table = "clips"
                Log.e("supadata_optionCalled", "channel1")
            }
            channel.join()

            val changeFlow: Flow<PostgresAction.Update> =
                channel.postgresChangeFlow(schema = "public") {
                    table = "clips"
                    //filter = "id=eq.${381}"
                    Log.e("supadata_optionCalled", "channel2")
                }


            changeFlow.collect {
                Log.e("supadata_optionCalled", "notification: " + it.decodeRecord<ClipsResp>())
            }

[Bug]: MissingFieldException while using signUp via Phone

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

Hello team.

I tried using the phone auth functionality of Supabase but I get a MissingFieldException while trying to sign up. What I am trying to achieve here is simple.

  • Call the signUp method by passing a phone number.
  • Send OTP to the phone number
  • Verify the OTP from the client.
  • Create user sucessfully.

Below is the code snippet that I used :

 try {
        val res = supabaseClient.gotrue.signUpWith(Phone){
                phoneNumber = phNumber
                password = passwordValue
            }
            Timber.d("Success")
            Timber.d("$res")
     } catch (exception : Exception) {
            Timber.e(exception)
        }

While calling this, I get a MissingFieldException and the result isn't being parsed for some reason. But, the user is getting created successfully on Supabase.

Phone login is enabled with Twillio and the config values have been set as expected.

I am not sure why this is happening and the OTP isn't getting delivered as well. Library versions are mentioned below.

Supabase version : 0.8.0
Kotlin version : 1.8.10

Relevant logs are mentioned below.

TIA :)

Platform(s)

Android

Relevant log output

kotlinx.serialization.MissingFieldException: Fields [id, phone, confirmation_sent_at, created_at, updated_at] are required for type with serial name 'io.github.jan.supabase.gotrue.providers.builtin.Phone.Result', but they were missing
                                                                                                    	at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.Phone$Result.<init>(Phone.kt:22)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.Phone$Result$$serializer.deserialize(Phone.kt:22)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.Phone$Result$$serializer.deserialize(Phone.kt:22)
                                                                                                    	at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:61)
                                                                                                    	at kotlinx.serialization.json.internal.AbstractJsonTreeDecoder.decodeSerializableValue(TreeJsonDecoder.kt:52)
                                                                                                    	at kotlinx.serialization.json.internal.TreeJsonDecoderKt.readJson(TreeJsonDecoder.kt:25)
                                                                                                    	at kotlinx.serialization.json.Json.decodeFromJsonElement(Json.kt:115)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.Phone.decodeResult(Phone.kt:36)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.Phone.decodeResult(Phone.kt:18)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.DefaultAuthProvider$DefaultImpls.signUp(DefaultAuthProvider.kt:96)
                                                                                                    	at io.github.jan.supabase.gotrue.providers.builtin.DefaultAuthProvider$signUp$1.invokeSuspend(Unknown Source:17)
                                                                                                    	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                    	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:938)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                    	at android.os.Looper.loop(Looper.java:223)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7656)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

[Feature request]: Support for calling stored procedures

General Info

  • I installed the latest version of SupaCompose
  • I checked for similar feature requests

Feature request

It'd be nice if we were able to easily call stored procedures in similar fashion as other db api calls.

Usecase

Obvious

[Bug]: 0.7.0-alpha-1 Getting timeout exception on every call

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

On 0.7.0-alpha-1 all network calls (at least from Auth and Postgrest) end up in timeout exception. Changing to 0.6.0 fixes the issue.

Platform(s)

Android

Relevant log output

No response

How do I update the user password?

What is your question?

How do I update the user password?.
I have tried to use client.gotrue.modifyUser(), but I don't know how, can someone show me an example?

[Bug]: java.lang.IllegalStateException: Plugin rest not installed or not of type class io.github.jan.supabase.postgrest.Postgrest

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

When I run the insert command:

override fun OnReceive(context:Context, intent: Intent?) {
   GlobalScope.launch { sendTheTextMessage(sender = messageSender, message = messageContent, date = messageDate, receiver = messageReceiver )  }
}
suspend fun sendTheTextMessage(sender: String, message: String, date: String, receiver: String){


       client.postgrest["text_messages"]
         .insert(Message(sender, message))
}

Platform(s)

Android

Relevant log output

java.lang.IllegalStateException: Plugin rest not installed or not of type class io.github.jan.supabase.postgrest.Postgrest
at io.github.jan.supabase.postgrest.PostgrestKt.getPostgrest(Postgrest.kt:92)
                                                                                                    	at com.nougatbits.nougatbitssmspushservice.MessageReceiverKt.sendTheTextMessage(MessageReceiver.kt:98)
                                                                                                    	at com.nougatbits.nougatbitssmspushservice.MessageReceiver$onReceive$1.invokeSuspend(MessageReceiver.kt:70)
                                                                                                    	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                    	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                    	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
                                                                                                    	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
                                                                                                    	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
                                                                                                    	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
                                                                                                    	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@33d62d8, Dispatchers.Default]

[Feature request]: OTP and sign up link verification on Desktop

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

There is currently no support for opening verification links on Desktop & automatically log into the desktop app.
Using a http callback server like for OAuth would not really make sense, as the user can verify their email whenever they want, including if the application is closed.

Feel free to suggest solutions

Note: Sign Up & OTP verification via a code is supported, so you can use that as a fallback

Usecase

Should be obvious

[Feature request]: Support Email OTP verification

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

Currently, GoTrue#verify is missing the parameter email and and VerifyType is missing VerifyType.MAGICLINK , to support
one-click signin via email like shown in here. Support for phone exists as GoTrue#verifyPhone

A possible implementation could look like this

client.gotrue.verifyEmail(email, token, VerifyType.MAGICLINK)

Usecase

Passwordless Signin and Signup via email (using OTP)

[Feature request]: Allow upserting into Storage bucket

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

The javascript API allows upserting data into a storage bucket by way of the upload() function, documented here-,Upload,-a%20file)

I'd love to see similar functionality in the Kotlin API, as right now using the upload() function to an existing path throws an error. If it's as simple as changing the method signature to something like suspend fun upload(path: String, data: ByteArray, upsert: Boolean): String and determining whether to call the POST or PUT based on the upsert parameter, that's a pull request I can submit myself, but I'm not sure if there are more considerations than just that.

Usecase

I don't want to have to check client-side if a URL already exists before uploading a file to a storage bucket, since the upsert functionality is already built into the Supabase API

[Bug]: Stately dependency breaks the build

General Info

  • I checked for similar bug report
  • I am using the latest version
  • I checked the troubleshooting page for similar problems

Version(s)

0.9.2

Target(s)

Android

What happened? (include your code)

After updating from 0.9.0 to 0.9.2 builds fail with Duplicate class co.touchlab.stately.HelpersJVMKt found in modules stately-common-jvm-2.0.0-rc1 (co.touchlab:stately-common-jvm:2.0.0-rc1) and stately-strict-jvm-2.0.0-rc1 (co.touchlab:stately-strict-jvm:2.0.0-rc1). Supabase-kt is the only library in my dependencies with transitive dependency to stately.

Steps To Reproduce (optional)

No response

Relevant log output (optional)

No response

[Question]: Is any HttpClient config needed to use Realtime?

What is your question?

When attempting to connect to realtime, I'm getting the following error when calling supabaseClient.realtime.connect():

Error while trying to connect to realtime websocket. Trying again in 7s
java.lang.IllegalArgumentException: Engine doesn't support WebSocketCapability
	at io.ktor.client.engine.HttpClientEngine$DefaultImpls.checkExtensions(HttpClientEngine.kt:105)
	at io.ktor.client.engine.HttpClientEngine$DefaultImpls.access$checkExtensions(HttpClientEngine.kt:24)
	at io.ktor.client.engine.HttpClientEngine$install$1.invokeSuspend(HttpClientEngine.kt:68)
	at io.ktor.client.engine.HttpClientEngine$install$1.invoke(Unknown Source:15)
	at io.ktor.client.engine.HttpClientEngine$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at io.ktor.client.plugins.HttpSend$DefaultSender.execute(HttpSend.kt:138)
	at io.ktor.client.plugins.HttpTimeout$Plugin$install$1.invokeSuspend(HttpTimeout.kt:146)
	at io.ktor.client.plugins.HttpTimeout$Plugin$install$1.invoke(Unknown Source:15)
	at io.ktor.client.plugins.HttpTimeout$Plugin$install$1.invoke(Unknown Source:6)
	at io.ktor.client.plugins.HttpSend$InterceptedSender.execute(HttpSend.kt:116)
	at io.ktor.client.plugins.HttpRedirect$Plugin$install$1.invokeSuspend(HttpRedirect.kt:64)
	at io.ktor.client.plugins.HttpRedirect$Plugin$install$1.invoke(Unknown Source:15)
	at io.ktor.client.plugins.HttpRedirect$Plugin$install$1.invoke(Unknown Source:6)
	at io.ktor.client.plugins.HttpSend$InterceptedSender.execute(HttpSend.kt:116)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$3.invokeSuspend(HttpCallValidator.kt:151)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$3.invoke(Unknown Source:13)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$3.invoke(Unknown Source:6)
	at io.ktor.client.plugins.HttpSend$InterceptedSender.execute(HttpSend.kt:116)
	at io.ktor.client.plugins.HttpSend$Plugin$install$1.invokeSuspend(HttpSend.kt:104)
	at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(Unknown Source:15)
	at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88)
	at io.ktor.client.plugins.websocket.WebSockets$Plugin$install$1.invokeSuspend(WebSockets.kt:169)
	at io.ktor.client.plugins.websocket.WebSockets$Plugin$install$1.invoke(Unknown Source:13)
	at io.ktor.client.plugins.websocket.WebSockets$Plugin$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:88)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:130)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(Unknown Source:13)
	at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:38)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(Unknown Source:11)
	at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(Unknown Source:4)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:120)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:78)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:98)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
	at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:191)
	at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:108)
	at io.ktor.client.plugins.websocket.BuildersKt$webSocketSession$2.invokeSuspend(builders.kt:239)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

I attempted to fix this by adding a custom HttpClient that has WebSockets installed, but that didn't fix the problem:

createSupabaseClient(
    supabaseUrl = "my_url",
    supabaseKey = "my_key"
) {
    // other stuff
    install(Realtime)
    httpEngine = HttpClient(Android) {
        install(WebSockets)
    }.engine
}

Is there any other setup needed to get Realtime working? I followed the wiki and setup docs, and checked out the Realtime demo, but it seems like I'm missing something.

[Feature request]: Order and Limit SQL modifier

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

Implement feature to order and limit SQL queries.

API could look like this:

client.postgrest["posts"].select { 
  order("created_at", Order.ASCENDING)
  limit(10)
}

Usecase

For my, and presumably many other, use-cases this is an essential feature.

[Feature request]: provide a BOM dependency

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

It'd be nice to provide a BOM dependency to simplify dependency version management.

Usecase

It's an easy way to avoid dependency version misconfiguration. You probably never want to use a different version of one module than the others.

[Bug]: install(GoTrue) throws error in native kotlin

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

suspend fun main() {


    val client = createSupabaseClient(
        supabaseUrl = url,
        supabaseKey = key
    ) {
        install(GoTrue)
        install(Postgrest)
    }
}

This code is in the Playground.kt file.
install(Postgrest) works fine in both native and Android environment.
install(GoTrue) works fine in Android environment but throws error in native.

Platform(s)

Native

Relevant log output

Exception in thread "main" java.lang.NullPointerException
	at com.russhwolf.settings.NoArgKt.Settings(NoArg.kt:32)
	at io.github.jan.supabase.gotrue.SettingsSessionManager.<init>(SessionManager.kt:26)
	at io.github.jan.supabase.gotrue.GoTrueImpl.<init>(GoTrueImpl.kt:51)
	at io.github.jan.supabase.gotrue.GoTrue$Companion.create(GoTrue.kt:311)
	at io.github.jan.supabase.gotrue.GoTrue$Companion.create(GoTrue.kt:305)
	at io.github.jan.supabase.SupabaseClientBuilder$install$2.invoke(SupabaseClientBuilder.kt:88)
	at io.github.jan.supabase.SupabaseClientBuilder$install$2.invoke(SupabaseClientBuilder.kt:87)
	at io.github.jan.supabase.SupabaseClientImpl.<init>(SupabaseClient.kt:79)
	at io.github.jan.supabase.SupabaseClientBuilder.build(SupabaseClientBuilder.kt:69)
	at io.github.ferhatwi.PlaygroundKt.main(Playground.kt:46)
	at io.github.ferhatwi.PlaygroundKt$main$2.invoke(Playground.kt)
	at io.github.ferhatwi.PlaygroundKt$main$2.invoke(Playground.kt)
	at kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt$createCoroutineUnintercepted$$inlined$createCoroutineFromSuspendFunction$IntrinsicsKt__IntrinsicsJvmKt$1.invokeSuspend(IntrinsicsJvm.kt:205)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115)
	at kotlin.coroutines.jvm.internal.RunSuspendKt.runSuspend(RunSuspend.kt:19)
	at io.github.ferhatwi.PlaygroundKt.main(Playground.kt)

[Bug]: HTTPS is used implicitly instead of specified HTTP URL

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

I specified a HTTP supabase url and the request got made using HTTPS.
I'm using the Supabase CLI for testing so this is a relevant use case for HTTP. (also selfhosted deployments would be another)

Setting a customUrl for the Postgrest plugin is my current working workaround for this:

install(Postgrest) {
    customUrl = "http://x.x.x.x:54321/rest/v1/"
}

The supabase-py project handles this case by printing a warning message if HTTP is used.

Platform(s)

Android

Relevant log output

Caused by: io.github.jan.supabase.exceptions.HttpRequestException: HTTP request to http://localhost?select=%2A (GET) failed with message: Invalid TLS record type code: 72
    at io.github.jan.supabase.network.KtorSupabaseHttpClient.request(KtorSupabaseHttpClient.kt:46)
    at io.github.jan.supabase.network.KtorSupabaseHttpClient$request$1.invokeSuspend(Unknown Source:15)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
    at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

[Question]: Unreasonable exeption when sign in with email.

What is your question?

I'm using GoTrue to build authentication in my app. After signing up, I use goTrue.loginWith(Email) and got an exception.
Did I miss any configuration?
Here's the message I got:

invalid_grant 
URL: https://jzdduyzfelmfniuebkre.supabase.co/auth/v1/token?grant_type=password&redirect_to=supabase%3A%2F%2Flogin
Headers: [apikey=[eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imp6ZGR1eXpmZWxtZm5pdWVia3JlIiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODA2OTUwODMsImV4cCI6MTk5NjI3MTA4M30.Eo29b7weMkAOucfGa0eRbb7fZR7Cpw1_Ifde_FV3zGc], Accept=[application/json], Accept-Charset=[UTF-8]]
Http Method: POST

How I provide GoTrue:

createSupabaseClient(
            supabaseUrl = BuildConfig.SUPABASE_URL,
            supabaseKey = BuildConfig.API_KEY
        ) {
            install(GoTrue)
        }.gotrue

How I call signin (authService has type of GoTrue):

authService.loginWith(Email) {
            this.email = email
            this.password = password
        }

Add new storage features introduced in LW7 updates

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

Feature request

Hi there,

There has been some features added to our storage, and we made some changes to the js client library to be able to use those features. It would be great if these could be added to this client library as well!

Usecase

Image quality optimization, more image transformations options, signed url for uploads.

[Feature request]: Add support for WASM

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

Kotlin for WASM is now in the alpha stage.
I would add support for Kotlin/WASM but a few dependencies are blocking it:

Core

GoTrue & Storage

  • multiplatform-settings
  • krypto

Usecase

Should be self-explainatory.

[Bug]: Postgrest plugin uses incorrect URL

General Info

  • I installed the latest version of SupaCompose
  • I checked for similar bug report

What happened? (include your code)

Tried to select from a table and URL called was
https://<something>.supabase.co/postgrest/v1/<tablename>
but based on docs it should have been
https://<something>.supabase.co/rest/v1/<tablename>

Platform(s)

Android

Relevant log output

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.supabasetest, PID: 15613
    io.github.jan.supacompose.exceptions.RestException:  (HTTP status 404)
        at io.github.jan.supacompose.postgrest.query.PostgrestBuilderKt.checkForErrorCodes(PostgrestBuilder.kt:141)
        at com.example.supabasetest.MainActivity$onCreate$1$1$1$1.invokeSuspend(MainActivity.kt:339)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:138)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:112)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:14)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:62)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:138)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:112)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:14)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:62)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:138)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:112)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:14)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:62)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:138)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:112)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:14)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:62)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:138)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:112)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(SuspendFunctionGun.kt:14)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:62)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
    	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@24dbc96, androidx.compose.runtime.BroadcastFrameClock@c933017, StandaloneCoroutine{Cancelling}@c1cac04, AndroidUiDispatcher@3b6a5ed]

[Bug]: On upload file mime-type always application/octet-stream

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

storage["main"].upload(
    "Folder/data.txt",
    File("data.txt").apply { writeText("Example text") }.readBytes()
)

image

I think the optimal solution is to use ContentType.defaultForFilePath(String)

append(HttpHeaders.ContentType, ContentType.defaultForFilePath(path))

Platform(s)

Desktop

Relevant log output

No response

[Feature request]: Specify database schema when using PostgREST

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

Is there an intended way to specify a database schema when using the PostgREST client? The wiki describes how to do it using Realtime however I couldn't find a proper solution for REST.

A possible solution/workaround is setting the request headers manually:

        createSupabaseClient(supabaseUrl, supabaseKey) {
            install(Postgrest)
            install(Realtime)
            httpConfig {
                defaultRequest {
                    header("Accept-Profile", "api")
                    header("Content-Profile", "api")
                }
            }
        }

It would be nice to be able to specify the schema in the client (like with supabase-js) and maybe override it per request (common feature request for supabase-js last time i checked)

Usecase

If you use any other database schema than public you would need this feature (or the workaround above). Different schemas are currently already supported for Realtime so it makes sense to also support it for REST.

[Bug]: Different timestamp behavior than in Supabase console

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

When attempting to compare timestamps with supabase-kt, the behavior seems to be different using the library than what I'm seeing in the Supabase console.

In the Supabase console, when I use the following query, I get a correct count of 4.

select count(finish_date)
from user_books
where user_id = 'some_user_id'
and reading_status = 'FINISHED'
and finish_date >= '2023-01-01T00:00:00Z'
and finish_date <= '2023-12-31T23:59:59.999999999Z'

But when I use the following call in the Kotlin client, I get a count of 43, which is the total number of rows with a reading_status of FINISHED for the given userId. It seems to be ignoring the date filtering entirely.

supabaseClient.postgrest.from("user_books")
            .select(columns = "finish_date", count = Count.EXACT) {
                eq("user_id", "some_user_id")
                eq("reading_status", "FINISHED")
                gte("finish_date", "2023-01-01T00:00:00Z")
                lte("finish_date", "2023-12-31T23:59:59.999999999Z")
            }

The result I'm getting back is what I would expect from the following query:

supabaseClient.postgrest.from("user_books")
            .select(columns = "finish_date", count = Count.EXACT) {
                eq("user_id", "some_user_id")
                eq("reading_status", "FINISHED")
            }

If I'm understanding correctly, the call from the Supabase console and the first Kotlin call should be equivalent, but they're returning different values. Not sure if this is a bug or if I'm misunderstanding the usage of the call on the Kotlin side.

When looking at the request from the kotlin side, this is the request header:

content-location=[/user_books?finish_date=lte.2023-12-31T23%3A59%3A59.999999999Z&reading_status=eq.FINISHED&select=finish_date&user_id=eq.0d5MrCrUMLPe6fWihwLGSVG1Ww43]

It has the lte filter, but not the gte one - is there a way to use both gte and lte to create a range?

Platform(s)

Android

Relevant log output

No response

[Bug]: A provider must be specified

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

Sign In with IDToken throws "A provider must be specified" even though a provider is specified.

put("provider", it.name)

returns null at

value.provider?.let {
    put("provider", it.name)
} ?: throw IllegalArgumentException("A provider must be specified.")

So new code should be:

value.provider?.aslo {
    put("provider", it.name)
} ?: throw IllegalArgumentException("A provider must be specified.")

to avoid null return of the put method.

Platform(s)

Android

Relevant log output

java.lang.IllegalArgumentException: A provider must be specified.
     at io.github.jan.supabase.gotrue.providers.builtin.DefaultAuthProvider$Config$Companion.serialize(DefaultAuthProvider.kt:58)

[Bug]: Response for RealtimeChannel.join() from server is ignored

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

When I create a Realtime channel and call join() the status changes to JOINING, but never to JOINED. If I debug RealtimeChannelImpl.onMessage(), I can see that there are two incoming messages:

  • RealtimeMessage(topic=realtime:commands, event=phx_reply, payload={"response":{"postgres_changes":[]},"status":"ok"}, ref=null)
  • RealtimeMessage(topic=realtime:commands, event=presence_state, payload={}, ref=null)

The required message for setting the status to JOINED is never received.

Code:

private val client = createSupabaseClient(
    "<redacted>",
    "<redacted>"
) {
    install(Realtime)
    httpConfig {
        install(ContentNegotiation) {
            json(json)
        }
    }
}

private val channel = client.realtime.createChannel("commands")

suspend fun send(command: ICommand) {
    CoroutineScope(Dispatchers.Default).launch {
        client.realtime.status.collect { status ->
            if (status == Realtime.Status.CONNECTED) {
                CoroutineScope(Dispatchers.Unconfined).launch {
                    channel.status.collect {
                        if (it == RealtimeChannel.Status.JOINED) {
                            println("Joined")
                            channel.broadcast("command", command, json)
                        }
                    }
                }
                channel.join()
            }
        }
    }
    client.realtime.connect()
}

Platform(s)

Desktop

Relevant log output

No response

[Bug]: Calling decodeRecord on ChannelAction delete produces NPE

General Info

  • I installed the latest version of SupaCompose
  • I check for similar bug report

What happened? (include your code)

Calling decodeRecord on ChannelAction delete produced NPE

The reason is the !! operator.

inline fun <reified T> ChannelAction.decodeRecord(json: Json = Json) = json.decodeFromJsonElement<T>(record!!)

The problem stems from record being defined in ChannelAction interface so it forces all inheritors to implement it. Probably better solution would be to split this functionality to a HasRecord interface, implement it only for valid ChannelActions and project decodeRecord over HasRecord instead of ChannelAction

I can tackle this one. Do you accept PRs?

Platform

Android

Relevant log output

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
    Process: com.example.supabasetest, PID: 13722
    java.lang.NullPointerException
        at com.example.supabasetest.MainActivity$onCreate$1$1$1$1$invokeSuspend$lambda-4$$inlined$on$3.onEvent(RealtimeChannelBuilder.kt:65)
        at io.github.jan.supacompose.realtime.RealtimeChannelImpl.onMessage(RealtimeChannel.kt:88)
        at io.github.jan.supacompose.realtime.RealtimeImpl.onMessage(Realtime.kt:219)
        at io.github.jan.supacompose.realtime.RealtimeImpl.access$onMessage(Realtime.kt:108)
        at io.github.jan.supacompose.realtime.RealtimeImpl$listenForMessages$1.invokeSuspend(Realtime.kt:182)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
    	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@ad55b75, Dispatchers.Default]
D/RealtimeImpl$onMessage: Received event DELETE for channel realtime:public:Points
I/Process: Sending signal. PID: 13722 SIG: 9

[Bug]: Could not serialize Email register response

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

I am running a self hosted SupaBase server with email "autoconfirm", so when a user registers he is automatically verified.
Therefore I believe the goTrue server does not provide the confirmation_sent_at field in the JSON response. Could this field be made optional as a simple fix?

Platform(s)

Android

Relevant log output

W/System.err: kotlinx.serialization.MissingFieldException: Fields [id, email, confirmation_sent_at, created_at, updated_at] are required for type with serial name 'io.github.jan.supabase.gotrue.providers.builtin.Email.Result', but they were missing

[Feature request]: Improve postgrest select syntax

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

As initially proposed in #80, it would be easier to restrict what columns you want to receive, by just specifying the type you want it to be decoded with later on.
I have a few examples for how we could do this and also have some negative aspects on some of them.

Option 1

Make PostgrestBuilder#select generic and use the classes properties as column restriction.
On top of that, remove the requirement of specifying of a generic parameter in PostgrestResult#decode functions

@Serializable
data class Product(val id: Int, val content: String)
//posgres table may be: id, content, author, created_at

val products = client.postgrest.select<Product>().decodeList()

//the responding payload only insists out of id and content, every other column is ignored

Notes:

  • You are required to decode using the type you specified in the select method
    -> No default values when serializing etc.
  • We have to fallback to the classes serial descriptor on Kotlin JS and Native in order to get to the class properties

Option 2

Make PostgrestBuilder#select generic and use the classes properties as column restriction.
Use custom type when decoding.

@Serializable
data class Product(val id: Int, val content: String)
//posgres table may be: id, content, author, created_at

val products = client.postgrest.select<Product>().decodeList<Product>()

//the responding payload only insists out of id and content, every other column is ignored
  • Forces you to specify the type twice
  • We have to fallback to the classes serial descriptor on Kotlin JS and Native in order to get to the class properties

Option 3

Replace the type of the columns parameter of PostgrestBuilder#select to something like Columns, which is a value class holding a string as its value.
You can create such class using it's companion object functions:

@Serializable
data class Product(val id: Int, val content: String)
//posgres table may be: id, content, author, created_at

val products = client.postgrest.select(Columns.ALL).decodeList<Product>()
//same as
val products = client.postgrest.select().decodeList<Product>() //ALL is default
val products = client.postgrest.select(Columns.list("id", "content")).decodeList<Product>()
val products = client.postgrest.select(Columns.type<Product>()).decodeList<Product>() 
//for readability
val products = postgrest["products"].select(
    columns = Columns.type<Product>()
) {
     lt("id", 10)
}.decodeSingle<Product>()
val products = client.postgrest.select(Columns.raw("id,content")).decodeList<Product>()

Notes:

  • On the type method: we have to fallback to the classes serial descriptor on Kotlin JS and Native in order to get to the class properties
  • May look verbose (?) but gives you the freedom on which columns you want to receive and how you want to decode your payload

Feel free to comment on this syntax.

Usecase

See initial PR

[Bug]: Wrong URL on BucketApi.downloadPublic()

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

A try to download file by url:
https://twmjqqkhwizjfmbebbxj.supabase.co/storage/v1/object/public/main/courses/0e324582-b99b-4be2-a48d-c651b45ec797/elements/6c868ee2-f13d-499b-8a61-c7f5b4c03221/data.txt
But a get error because the request is built incorrectly:
https://twmjqqkhwizjfmbebbxj.supabase.co/storage/v1/https://twmjqqkhwizjfmbebbxj.supabase.co/storage/v1/object/public/main/courses/0e324582-b99b-4be2-a48d-c651b45ec797/elements/6c868ee2-f13d-499b-8a61-c7f5b4c03221/data.txt

I haven't checked, but I'm guessing there's also a problem with the request url build in the 'downloadAuthenticated' method:

Platform(s)

Desktop

Relevant log output

No response

[Question]: Adding data to a column with array type

What is your question?

Hi! I'm currently working on a project involving a QR scanner that routinely adds the timestamp of when it captured a certain QR code into an array. I worked out how to send a timestamp (using a string) but now I can't figure out how to send an array of timestamps.

Is there a certain syntax for pushing a new value to an array inside the timestamp array column? Should I just GET the whole array, dump it into a string, remove the bracket and add the timestamp, and join the whole thing again make it look like an array? I feel like I'm not getting something, like there should be an easier way to go about this.

Thanks!

service role cannot bypass row-level security

General Info

  • I checked for similar bug report
  • I am using the latest version
  • I checked the troubleshooting page for similar problems
  • I enabled logging and checked the logs

Version(s)

0.9.3

Target(s)

Android

What happened? (include your code)

I use service_role key and wish to bypass row-level security, but I got error.

  var client = createSupabaseClient(supabaseUrl = "url",
      supabaseKey = "service_role"
  ){
      install(Postgrest)
  }
  client.postgrest["xxx"].insert(
          xxx, returning = Returning.MINIMAL
 )
io.github.jan.supabase.exceptions.UnauthorizedRestException: new row violates row-level security policy for table "xxx"
2023-05-14 23:06:27.382 12035-12035 System.err              pid-12035                            W  URL: xxx
2023-05-14 23:06:27.382 12035-12035 System.err              pid-12035                            W  Headers: xxx
2023-05-14 23:06:27.382 12035-12035 System.err              pid-12035                            W  Http Method: POST
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at io.github.jan.supabase.postgrest.PostgrestImpl.parseErrorResponse(Postgrest.kt:97)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at io.github.jan.supabase.gotrue.AuthenticatedSupabaseApiKt$authenticatedSupabaseApi$3.invoke(AuthenticatedSupabaseApi.kt:40)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at io.github.jan.supabase.gotrue.AuthenticatedSupabaseApiKt$authenticatedSupabaseApi$3.invoke(AuthenticatedSupabaseApi.kt:40)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at io.github.jan.supabase.network.SupabaseApi.rawRequest$suspendImpl(SupabaseApi.kt:21)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at io.github.jan.supabase.network.SupabaseApi$rawRequest$1.invokeSuspend(Unknown Source:15)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at android.os.Handler.handleCallback(Handler.java:883)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at android.os.Handler.dispatchMessage(Handler.java:100)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at android.os.Looper.loop(Looper.java:227)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at android.app.ActivityThread.main(ActivityThread.java:7550)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at java.lang.reflect.Method.invoke(Native Method)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
2023-05-14 23:06:27.383 12035-12035 System.err              pid-12035                            W  	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:953)

Steps To Reproduce (optional)

No response

Relevant log output (optional)

No response

[Question]: Why doesn't it return the list of files?

What is your question?

var bucketAds = Client.client.storage["ads"]
var listBucket = bucketAds.list("vs_")

println(listBucket.size)

The function returns 0 when it shouldn't be, since there are files in the storage

[Feature request]: Improve rest exceptions or use a more functional pattern

General Info

  • I installed the latest version of Supabase Kt
  • I checked for similar feature requests

Feature request

Currently, there's primarily one exception type: RestException which is hard to catch because you don't know exactly whats causing the Rest Exception without parsing the raw error.
Now the library could either parse the exception and throw corresponding exceptions (1) or use a more functional pattern which forces developers to handle the result (maybe using arrow-kt ?) (2).
Independently of that, results of Postgrest Calls must be improved severely
Example for (1)

try {
   gotrue.getUser("id")
} catch(e: UnauthorizedException) {

}

Example 1 for (2)

val result = gotrue.getUser("id")
when(result) {
      is Result.Success -> //
      is Result.Unauthorized -> //
}

Example 2 for (2) using arrow-kt (which has the advantage of already being there, and could be implemented easily)

val result = gotrue.getUser("id")
when(result) {
  is Either.Left -> when (result.value) {
    is UnauthorizedException -> //
    is IllegalArgumentException ->//
    else -> "Unknown error"
  }
  is Either.Right -> println(result.id)
}

Usecase

Error Handling

[Bug]: When signUp, Id returned null

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

When I was trying to signUp for my user test, I was expecting for getting an User Id from the response, the signUp succeeded, the UserId displayed in Supabase, but it returned null in my console.

Here's my code:

User:

@Serializable
data class User(
    @SerialName("id") val userId: String?,
    val name: String,
    val role: String,
    val token: String?
)

Insert Function:

suspend fun insertUserToDB(
        id: String?,
        name: String,
        role: Role,
        token: String?
    ): Flow<ResponseStatus<Boolean>> {
        return flow {
            emit(ResponseStatus.Loading)
            try {
                client.postgrest["tbl_users"]
                    .insert(
                        User(
                            userId = id,
                            name = name,
                            role = role.value,
                            token = token
                        )
                    )
                emit(ResponseStatus.Success(true))
            } catch (e: Exception) {
                emit(ResponseStatus.Error(e.message ?: "Error when inserting user to database"))
            }
        }
    }

Sign Up Process:

fun register(email: String, password: String): Flow<ResponseStatus<String?>> {
        return flow {
            emit(ResponseStatus.Loading)
            try {
                val result = client.gotrue.signUpWith(Email) {
                    this.email = email
                    this.password = password
                }
                Log.d("RESULT", result?.id.toString())
                emit(ResponseStatus.Success(result?.id))
            } catch (e: Exception) {
                Log.d("REGISTER_ERR", e.toString())
                emit(ResponseStatus.Error(e.message ?: "Error occurred when Register"))
            }
        }
    }
repository.register(
    _emailInputState.value ,
    _passwordInputState.value
).collectLatest    {
        status ->
        when (status) {
            is ResponseStatus.Error -> {
                _registerStatus.emit(RegisterScreenUiEvent.Error(status.message))
            }
            is ResponseStatus.Loading -> {
                _registerStatus.emit(RegisterScreenUiEvent.Loading)
            }
            is ResponseStatus.Success -> {
                _registerStatus.emit(RegisterScreenUiEvent.Loading)
                insertToDB(status.data) // <- It has to be User Id from Sign Up Process
            }
        }
    }

Insert Process:

private suspend fun insertToDB(id: String?) {
        repository.insertUserToDB(
            id, // <- Null here
            _usernameInputState.value,
            _roleInputState.value,
            null,
        ).collectLatest { status ->
              ...
        }

Platform(s)

Android

Relevant log output

D/ERR: null value in column "id" of relation "tbl_users" violates not-null constraint :(Failing row contains (null, 2023-03-16 02:35:57.806223+00, mamang, Guru, null).)
    URL: URL
    Headers: [Authorization=[Bearer apikey], Prefer=[return=representation], Content-Profile=[public], apikey=[apikey], Accept=[application/json], Accept-Charset=[UTF-8]]
    Http Method: POST

[Bug]: When using signUp with different execution contexts

General Info

  • I installed the latest version of Supabase-Kt

Version(s)

0.8.5

Target(s)

Android

What happened? (include your code)

I am implementing the registry and I get an error when I change the context to the IO

Here's my code with the IO execution context:

class MainActivitySuperBase : AppCompatActivity() {

    private val TAG = "SuperBase"
    lateinit var binding: ActivityMainSuperBaseBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainSuperBaseBinding.inflate(layoutInflater)
        setContentView(binding.root)



        binding.ingresar.setOnClickListener {
            lifecycleScope.launch {
                Log.d(TAG, "RUN  ${Thread.currentThread().name}")
                login()
            }
        }
    }

     private suspend fun login() {
        withContext(Dispatchers.IO) { /* <---- I change the context here */
            kotlin.runCatching {
                client.gotrue.signUpWith(Email) {
                    email = "[email protected]"
                    password = "123456789"
                }
            }.onSuccess {
                Log.d(TAG, "Successfully registered! Check your E-Mail to verify your account.")
            }.onFailure {
                Log.d(TAG, "There was an error while registering: ${it}")
            }
        }
    }

And the error I get is:

 There was an error while registering: java.lang.ExceptionInInitializerError 
 or 
 There was an error while registering: null

But when I change the execution context to Main it works fine.

Here's my code with the Main execution context

class MainActivitySuperBase : AppCompatActivity() {

    private val TAG = "SuperBase"
    lateinit var binding: ActivityMainSuperBaseBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainSuperBaseBinding.inflate(layoutInflater)
        setContentView(binding.root)



        binding.ingresar.setOnClickListener {
            lifecycleScope.launch {
                Log.d(TAG, "RUN  ${Thread.currentThread().name}")
                login()
            }
        }
    }

    private suspend fun login() {
        kotlin.runCatching {
            client.gotrue.signUpWith(Email) {
                email = "[email protected]"
                password = "123456789"
            }
        }.onSuccess {
            Log.d(TAG, "Successfully registered! Check your E-Mail to verify your account.")
        }.onFailure {
            Log.d(TAG, "There was an error while registering: ${it}")
        }
    }
}

I would like to know if this is a bug or an implementation issue.
I am learning android and from what I have learned the use of Dispatchers.IO is used for input/output intensive operations, such as reading or writing files, network calls, etc.
If you can help me I would really appreciate it.

Steps To Reproduce (optional)

No response

Relevant log output (optional)

There was an error while registering: java.lang.ExceptionInInitializerError 
or 
There was an error while registering: null

[Bug]: headers must have required property 'authorization'

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

I was trying to get a list of files in a folder, but it requires 'authorization' in the header. There is only apiKey.

request:

val items = storage["mybucket"].list("courses")

client:

createSupabaseClient(
            supabaseUrl = SupabaseConstants.url,
            supabaseKey = SupabaseConstants.key
        ) {
            install(Realtime)
            install(Storage)
        }

Platform(s)

Desktop

Relevant log output

Error :(headers must have required property 'authorization')
URL: https://***.supabase.co/storage/v1/object/list/mybucket
Headers: [apikey=[***], Accept=[application/json], Accept-Charset=[UTF-8]]
Http Method: POST
io.github.jan.supabase.exceptions.BadRequestRestException: Error :(headers must have required property 'authorization')
URL: https://***.supabase.co/storage/v1/object/list/mybucket
Headers: [apikey=[***], Accept=[application/json], Accept-Charset=[UTF-8]]
Http Method: POST
	at app//io.github.jan.supabase.storage.StorageImpl.parseErrorResponse(Storage.kt:140)
	at app//io.github.jan.supabase.gotrue.AuthenticatedSupabaseApiKt$authenticatedSupabaseApi$3.invoke(AuthenticatedSupabaseApi.kt:38)
	at app//io.github.jan.supabase.gotrue.AuthenticatedSupabaseApiKt$authenticatedSupabaseApi$3.invoke(AuthenticatedSupabaseApi.kt:38)
	at app//io.github.jan.supabase.network.SupabaseApi.request$suspendImpl(SupabaseApi.kt:17)
	at app//io.github.jan.supabase.network.SupabaseApi$request$1.invokeSuspend(SupabaseApi.kt)
	at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at app//kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at app//kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
	at app//kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

[Bug]: kotlinx.serialization.SerializationException: Serializer for class 'Select' is not found.

General Info

  • I installed the latest version of SupaCompose
  • I checked for similar bug report

What happened? (include your code)

Since f580a15 Postgrest::select fails with kotlinx.serialization.SerializationException: Serializer for class 'Select' is not found.

Platform(s)

Android

Relevant log output

kotlinx.serialization.SerializationException: Serializer for class 'Select' is not found.
    Mark the class as @Serializable or provide the serializer explicitly.
        at kotlinx.serialization.internal.Platform_commonKt.serializerNotRegistered(Platform.common.kt:91)
        at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:157)
        at kotlinx.serialization.SerializersKt.serializer(Unknown Source:1)
        at io.ktor.serialization.kotlinx.SerializerLookupKt.guessSerializer(SerializerLookup.kt:44)
        at io.ktor.serialization.kotlinx.KotlinxSerializationBase.serialize$ktor_serialization_kotlinx(KotlinxSerializationBase.kt:34)
        at io.ktor.serialization.kotlinx.KotlinxSerializationConverter.serializeNullable(KotlinxSerializationConverter.kt:54)
        at io.ktor.client.plugins.contentnegotiation.ContentNegotiation.convertRequest$ktor_client_content_negotiation(ContentNegotiation.kt:156)
        at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invokeSuspend(ContentNegotiation.kt:202)
        at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invoke(Unknown Source:11)
        at io.ktor.client.plugins.contentnegotiation.ContentNegotiation$Plugin$install$1.invoke(Unknown Source:4)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:91)
        at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:126)
        at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(Unknown Source:13)
        at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(Unknown Source:4)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
        at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:35)
        at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(Unknown Source:11)
        at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(Unknown Source:4)
        at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
        at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
        at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:101)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:187)
        at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:107)
        at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:46)
        at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:61)
        at io.github.jan.supacompose.postgrest.request.PostgrestRequest$DefaultImpls.execute(PostgrestRequest.kt:143)
        at io.github.jan.supacompose.postgrest.request.PostgrestRequest$Select.execute(PostgrestRequest.kt:56)
        at com.github.brezinajn.stalker.MainActivity$onCreate$1$1$1$2.invokeSuspend(MainActivity.kt:228)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
        at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
        at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
    	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@3b5ddde, androidx.compose.runtime.BroadcastFrameClock@5bd4bbf, StandaloneCoroutine{Cancelling}@367a28c, AndroidUiDispatcher@aef0dd5]

[Bug]: Getting Error_0: Fail to fetch on jS database call

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

I am getting the following error when I am trying to make a database call.

Error_0: Fail to fetch
Error_0: Fail to fetch
	at <global>.<unknown>(C:/Users/laure/AppData/Local/Temp/_karma_webpack_467611/commons.js:82924)

The expected function in common

expect suspend fun getUserDetails(userId: Int): UserDetails

@Serializable
data class UserDetails(
    @SerialName("user_id") val userId: Int,
    @SerialName("user_overal_review")  val userOverallReview: Float?,
    @SerialName("user_reviews_number") val userReviewsNumber: Int?,
    @SerialName("first_name")  val firstName: String,
    @SerialName("last_name")  val lastName: String,
    @SerialName("user_about_me")  val aboutMe: String?,
    @SerialName("user_other")  val other: String?
)
actual suspend fun getUserDetails(userId: Int): UserDetails {
    val supabaseClient = createSupabaseClient(
        "url", "apikey"
    ) {
        install(Postgrest) {
        }
    }

   val postGrestResult = supabaseClient.postgrest.from("usersdetails").select{
            eq("user_id", userId)
        }
    return postGrestResult.decodeSingle()
}
@JsExport
@ExperimentalJsExport
@Suppress("NON_EXPORTABLE_TYPE")
fun getUserDetailsPromise(userId: Int) : Promise<UserDetails> {
    return GlobalScope.promise {
        getUserDetails(userId)
    }
}

I am calling the getUserDetailsPromise and I am receiving that error, I have a similar function for JVM and it works just fine.

Library: implementation("io.ktor:ktor-client-js:2.2.1")

Platform(s)

Web

Relevant log output

No response

[Bug]: Initialise supposeClient realtime

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

class SplashKotlinActivity : AppCompatActivity() {

val supabaseClient = createSupabaseClient {
    supabaseUrl = "https://MY_KEY.supabase.co/realtime/v1"
    supabaseKey = "SUPABASE_KEY"

    install(Realtime)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_splash)
    initializeAndroid(supabaseClient)

}

Run app and it crases and trows errro: java.lang.ExceptionInInitializerError

Platform(s)

Android

Relevant log output

java.lang.ExceptionInInitializerError
        at io.ktor.client.HttpClientJvmKt.HttpClient(Unknown Source:0)
        at io.github.jan.supacompose.SupabaseClientImpl.<init>(SupabaseClient.kt:94)
        at io.github.jan.supacompose.SupabaseClientBuilder.build(SupabaseClientBuilder.kt:30)
        at com.wweevv.SplashKotlinActivity.<init>(SplashKotlinActivity.kt:65)
        at java.lang.Class.newInstance(Native Method)
        at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
        at android.app.Instrumentation.newActivity(Instrumentation.java:1272)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3389)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3620)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2183)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:241)
        at android.app.ActivityThread.main(ActivityThread.java:7617)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
     Caused by: java.lang.IllegalStateException: Failed to find HTTP client engine implementation in the classpath: consider adding client engine dependency.

[Question]: I'm having trouble getting realtime flow of updates to work

Wondering how to get real time working

quick code snippet:

    private val channel = client.realtime.createChannel("channelId")
    private val messageFlow: Flow<PostgresAction.Insert> = channel.postgresChangeFlow(schemaName) {
        table = messageTableName
    }

    val newMessageFlow: Flow<Message> =
        messageFlow.map {
            it.decodeRecord<ReceiveMessage>()
        }.map { Message(it.content, true) }

    suspend fun init() {
        client.realtime.connect()
        channel.join()
    }

i'm inserting new rows, and putting a breakpoint on it.decodeRecord() but not seeing anything happen. quite new to this so i assume it's probably use error.

[Bug]: Serializer for class 'Config' is not found

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

Attempting to use email signup in a kotlin/js module with the following code:

		val result = supabaseClient.gotrue.signUpWith(Email) {
			this.email = username
			this.password = password
		}

		console.log(result)

which i expect to trigger an email signup on supabase. However it fails in the browser.

Platform(s)

Web

Relevant log output

Object { message: "Serializer for class 'Config' is not found.\nMark the class as @Serializable or provide the serializer explicitly.\nOn Kotlin/JS explicitly declared serializer should be used for interfaces and enums without @Serializable annotation", cause: undefined, name: "si", stack: "Bl@http://127.0.0.1:8080/static/frontend.js:75:490599\nai@http://127.0.0.1:8080/static/frontend.js:75:592296\n3645/i</_i/i<@http://127.0.0.1:8080/static/frontend.js:75:594117\n_i@http://127.0.0.1:8080/static/frontend.js:75:594360\n158/r/mr.prototype.j4t@http://127.0.0.1:8080/static/frontend.js:75:1270651\n158/r/mr.prototype.z4s@http://127.0.0.1:8080/static/frontend.js:75:1270752\n158/r/lr.prototype.ui@http://127.0.0.1:8080/static/frontend.js:75:1267732\n158/r/mr.prototype.u4n@http://127.0.0.1:8080/static/frontend.js:75:1285661\n158/r/Sn.prototype.b4i@http://127.0.0.1:8080/static/frontend.js:75:1260018\n158/r/Sn.prototype.c4i@http://127.0.0.1:8080/static/frontend.js:75:1284963\n1060/r/$r.prototype.ui@http://127.0.0.1:8080/static/frontend.js:75:1203331\n1060/r/gr.prototype.y4u@http://127.0.0.1:8080/static/frontend.js:75:1203714\n1060/r/yi.prototype.ui@http://127.0.0.1:8080/static/frontend.js:75:1213873\n1060/r/yi.prototype.h1i@http://127.0.0.1:8080/static/frontend.js:75:1213596\ni@http://127.0.0.1:8080/static/frontend.js:75:1187330\n8744/n/wp.prototype.ui@http://127.0.0.1:8080/static/frontend.js:75:563546\n8744/n/mp.prototype.ti@http://127.0.0.1:8080/static/frontend.js:75:562805\n8744/n/mp.prototype.c4@http://127.0.0.1:8080/static/frontend.js:75:563063\n7646/r/oa.prototype.tp@http://127.0.0.1:8080/static/frontend.js:75:820984\n7646/r/Wa.prototype.f19@http://127.0.0.1:8080/static/frontend.js:75:825087\n7646/r/Ga.prototype.g19/<@http://127.0.0.1:8080/static/frontend.js:75:825853\npromise callback*7646/r/Ga.prototype.g19@http://127.0.0.1:8080/static/frontend.js:75:825819\n7646/r/Wa.prototype.i19@http://127.0.0.1:8080/static/frontend.js:75:824967\n7646/r/Ka.prototype.uq@http://127.0.0.1:8080/static/frontend.js:75:825556\n7646/r/za.prototype.uq@http://127.0.0.1:8080/static/frontend.js:75:823335\nta@http://127.0.0.1:8080/static/frontend.js:75:760901\n7646/r/ma/<@http://127.0.0.1:8080/static/frontend.js:75:762646\nma@http://127.0.0.1:8080/static/frontend.js:75:762736\n7646/r/Gn.prototype.bl@http://127.0.0.1:8080/static/frontend.js:75:783241\n7646/r/He.prototype.yk@http://127.0.0.1:8080/static/frontend.js:75:772459\n7646/r/t.$_$.m/<@http://127.0.0.1:8080/static/frontend.js:75:831141\n7646/r/t.$_$.m@http://127.0.0.1:8080/static/frontend.js:75:831153\n1060/r/di/</</n.onClick@http://127.0.0.1:8080/static/frontend.js:75:1187256\nPt@http://127.0.0.1:8080/static/frontend.js:75:281161\nFt@http://127.0.0.1:8080/static/frontend.js:75:281315\n3936/Mr/<@http://127.0.0.1:8080/static/frontend.js:75:301175\nMr@http://127.0.0.1:8080/static/frontend.js:75:301269\nzr@http://127.0.0.1:8080/static/frontend.js:75:301685\n3936/Zr/<@http://127.0.0.1:8080/static/frontend.js:75:307113\nll@http://127.0.0.1:8080/static/frontend.js:75:370407\nIt@http://127.0.0.1:8080/static/frontend.js:75:280294\nZr@http://127.0.0.1:8080/static/frontend.js:75:302977\nVe@http://127.0.0.1:8080/static/frontend.js:75:287394\nBe@http://127.0.0.1:8080/static/frontend.js:75:287176\nEventListener.handleEvent*Hr@http://127.0.0.1:8080/static/frontend.js:75:302482\nLr@http://127.0.0.1:8080/static/frontend.js:75:301881\n3936/Ur/<@http://127.0.0.1:8080/static/frontend.js:75:302047\nUr@http://127.0.0.1:8080/static/frontend.js:75:301991\n3936/e.createRoot@http://127.0.0.1:8080/static/frontend.js:75:391896\n1060/r/<@http://127.0.0.1:8080/static/frontend.js:75:1232697\nr@http://127.0.0.1:8080/static/frontend.js:75:1232843\n1060@http://127.0.0.1:8080/static/frontend.js:75:1232852\n__webpack_require__@http://127.0.0.1:8080/static/frontend.js:75:1295711\n@http://127.0.0.1:8080/static/frontend.js:75:1296908\n@http://127.0.0.1:8080/static/frontend.js:75:1296943\n@http://127.0.0.1:8080/static/frontend.js:2:193\n@http://127.0.0.1:8080/static/frontend.js:2:197\n" }
CoroutineExceptionHandlerImpl.kt:11:4

[Question]: Is it possible to update data without a DTO?

What is your question?

I would like to dynamically update data over postgrest by using a binding to my internal datastructure. It seems that in the supabase-community/postgrest-kt, this is possible, however I could not find a way to achieve the same with supabase-kt without using a DTO:

override suspended fun publishValue(key: String, data: Any) {
    val result = client.postgrest["mytablename"].update {
        key to data
    }
}

How can this be achieved without using a specific DTO?

[Bug]: Initialization of GraphQL leads to stack overflow

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

On 0.8.1 when creating client

createSupabaseClient(
        supabaseUrl = url,
        supabaseKey = key,
    ) {
        install(GoTrue)
        install(Realtime)
        install(Postgrest)
        install(Storage)
        install(GraphQL)
    }

this leads to stack overflow.

Platform(s)

Android

Relevant log output

E/AndroidRuntime:     at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
E/AndroidRuntime:     at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:58)
        at io.github.jan.supabase.graphql.GraphQL$Companion.setup(GraphQL.kt:43)
        at io.github.jan.supabase.SupabaseClientBuilder.install(SupabaseClientBuilder.kt:86)
        at io.github.jan.supabase.SupabaseClientBuilder.install$default(SupabaseClientBuilder.kt:84)
        at com.github.brezinajn.stalker.MainActivityKt.SupabaseClient(MainActivity.kt:60)
        at com.github.brezinajn.stalker.MainActivity.onCreate(MainActivity.kt:91)
        at android.app.Activity.performCreate(Activity.java:8051)
        at android.app.Activity.performCreate(Activity.java:8031)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7839)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

[Bug]: GraphQL queries fail with 404

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

When trying to perform query the execution ends up with status 404.
Failure(com.apollographql.apollo3.exception.ApolloHttpException: Http request failed with status code `404`)

In addition it seems the client is trying to contact localhost:
http://localhost?latitude=not.neq.0.0&longitude=not.neq.0.0&select=%2A
Edit: My bad. Incorrect log. Disregard that please.

Further testing is currently being blocked by #61

Platform(s)

Android

Relevant log output

No response

[Bug]: Modules don't recognize supabaseUrl on Android environment.

General Info

  • I installed the latest version of Supabase-Kt
  • I checked for similar bug report

What happened? (include your code)

package io.github.ferhatwi.presentation.main

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import io.github.ferhatwi.*
import io.github.jan.supabase.createSupabaseClient
import io.github.jan.supabase.postgrest.Postgrest
import io.github.jan.supabase.postgrest.postgrest
import kotlinx.coroutines.launch
import java.util.*

@AndroidEntryPoint
class Main : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val client = createSupabaseClient(
            supabaseUrl = url,
            supabaseKey = key
        ) {
            install(Postgrest)
        }

        lifecycleScope.launch {
            val y = client.postgrest["test"].select()
            println(y)
        }

        setContent {
            MainScreen()
        }
    }
}

client.postgrest["test"].select() method sends request to localhost instead of the url that I've provided. http://localhost?select=%2A is the exact request.
This exact method works fine in native.

Platform(s)

Android

Relevant log output

/AndroidRuntime: FATAL EXCEPTION: main
    Process: io.github.ferhatwi, PID: 20952
    io.github.jan.supabase.exceptions.HttpRequestException: HTTP request to http://localhost?select=%2A (GET) failed with message: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
        at io.github.jan.supabase.network.KtorSupabaseHttpClient.request(KtorSupabaseHttpClient.kt:46)
        at io.github.jan.supabase.network.KtorSupabaseHttpClient$request$1.invokeSuspend(Unknown Source:15)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at kotlinx.coroutines.EventLoop.processUnconfinedEvent(EventLoop.common.kt:69)
        at kotlinx.coroutines.internal.DispatchedContinuation.resumeWith(DispatchedContinuation.kt:355)
        at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:138)
        at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:11)
        at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:55)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
        at android.os.Handler.handleCallback(Handler.java:942)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7872)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
    	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@e00b58a, Dispatchers.Main.immediate]

[Bug]: RPC throws NoTransformationFoundException for functions that returns void

General Info

  • I checked for similar bug report

Version(s)

0.9.0

Target(s)

Android

What happened? (include your code)

Calling a supabase function that returns void, throws NoTransformationFoundException.
It probably tries to convert result body to JsonElement. Since result has no content, JsonElement doesn't get created.

Setting head to true or false doesn't change the output, still throws.

Steps To Reproduce (optional)

No response

Relevant log output (optional)

Exception in thread "main" io.ktor.client.call.NoTransformationFoundException: No transformation found: class io.ktor.utils.io.ByteBufferChannel -> class kotlinx.serialization.json.JsonElement
with response from https://PROJECT-URL.supabase.co/rest/v1/rpc/void_test:
status: 204 No Content

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.