mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Update Kotlin docs for 2.0.0 (#18912)
* Rename gotrue to auth * update columns * rename gotrue to auth (again) * improve postgrest docs * add new modules * rename logout * Rename some more stuff * Rename more stuff * Rename guides * Rename SSO docs * Rename "phoneNumber" to "phone" * rename some more stuff * Add v2 docs * Rename postgrest[..] to supabase.from(..) * Migrate postgrest to new syntax * Add explain, single & csv * Rename storage * Rename some more storage storage methods * fix invalid docs * fix duplicate id * exclude sections for kotlin * Rename password reset method * Update tutorial * Update realtime docs * Update more realtime docs * Update module docs * add link to migration guide * update installing * document custom KotlinX Serializer * update code to pass formatter * Remove supabase.realtime.connect() docs * fix typo * update kotlin quick start guide * add a note about making network request from the UI code * run formatter * add small kotlinx serialization change * Apply suggestions from code review Co-authored-by: Charis <26616127+charislam@users.noreply.github.com> * improve quickstart --------- Co-authored-by: Tyler <18113850+dshukertjr@users.noreply.github.com> Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>
This commit is contained in:
49 files changed
+4839
-682
No files matched your search
@@ -208,7 +208,7 @@ export const REFERENCES: References = {
|
||||
kotlin: {
|
||||
name: 'Kotlin',
|
||||
library: 'supabase-kt',
|
||||
versions: ['v1'],
|
||||
versions: ['v2', 'v1'],
|
||||
icon: '/docs/img/libraries/kotlin-icon.svg',
|
||||
},
|
||||
cli: {
|
||||
@@ -1624,7 +1624,14 @@ export const reference_swift_v1 = {
|
||||
parent: '/reference',
|
||||
}
|
||||
|
||||
export const reference_kotlin_v0 = {
|
||||
export const reference_kotlin_v1 = {
|
||||
icon: 'reference-kotlin',
|
||||
title: 'kotlin',
|
||||
url: 'guides/reference/kotlin',
|
||||
parent: '/reference',
|
||||
}
|
||||
|
||||
export const reference_kotlin_v2 = {
|
||||
icon: 'reference-kotlin',
|
||||
title: 'kotlin',
|
||||
url: 'guides/reference/kotlin',
|
||||
@@ -1754,7 +1761,7 @@ export const references = [
|
||||
},
|
||||
{
|
||||
label: 'supabase-kt',
|
||||
versions: ['v0'],
|
||||
versions: ['v2', 'v1'],
|
||||
description: 'something about the reference',
|
||||
icon: '/docs/img/icons/kotlin-icon.svg',
|
||||
url: '/reference/kotlin/start',
|
||||
|
||||
@@ -159,12 +159,19 @@ const menus: Menu[] = [
|
||||
type: 'reference',
|
||||
},
|
||||
{
|
||||
id: 'reference_kotlin_v0',
|
||||
path: '/reference/kotlin',
|
||||
id: 'reference_kotlin_v1',
|
||||
path: '/reference/kotlin/v1',
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_kt_v1.yml',
|
||||
type: 'reference',
|
||||
},
|
||||
{
|
||||
id: 'reference_kotlin_v2',
|
||||
path: '/reference/kotlin',
|
||||
commonSectionsFile: 'common-client-libs-sections.json',
|
||||
specFile: 'supabase_kt_v2.yml',
|
||||
type: 'reference',
|
||||
},
|
||||
{
|
||||
id: 'reference_cli',
|
||||
path: '/reference/cli',
|
||||
|
||||
@@ -51,7 +51,17 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supab
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
The available modules are: [**gotrue-kt**](https://github.com/supabase-community/supabase-kt/tree/master/GoTrue), [**realtime-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Realtime), [**storage-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Storage), [**functions-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Functions), [**postgrest-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Postgrest), [**apollo-graphql**](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ApolloGraphQL), [**compose-auth**](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ComposeAuth) and [**compose-auth-ui**](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ComposeAuthUI)
|
||||
The available modules are:
|
||||
- [**gotrue-kt**](https://github.com/supabase-community/supabase-kt/tree/master/GoTrue)
|
||||
- [**realtime-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Realtime)
|
||||
- [**storage-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Storage)
|
||||
- [**functions-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Functions)
|
||||
- [**postgrest-kt**](https://github.com/supabase-community/supabase-kt/tree/master/Postgrest)
|
||||
- [apollo-graphql](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ApolloGraphQL) - Creates an [Apollo GraphQL Client](https://github.com/apollographql/apollo-kotlin) for interacting with the Supabase API.
|
||||
- [compose-auth](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ComposeAuth) - Provides easy Native Google & Apple Auth for Compose Multiplatform targets.
|
||||
- [compose-auth-ui](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ComposeAuthUI) - Provides UI Components for Compose Multiplatform.
|
||||
- [coil-integration](https://github.com/supabase-community/supabase-kt/tree/master/plugins/CoilIntegration) - Provides a [Coil](https://github.com/coil-kt/coil) Integration for displaying images stored in Supabase Storage.
|
||||
- [imageloader-integration](https://github.com/supabase-community/supabase-kt/tree/master/plugins/ImageLoaderIntegration) - Provides a [Compose ImageLoader](https://github.com/qdsfdhvh/compose-imageloader) Integration for displaying images stored in Supabase Storage.
|
||||
|
||||
When using multiple modules, you can also use the BOM dependency to ensure that all modules use the same version:
|
||||
|
||||
@@ -265,7 +275,10 @@ By default, [KotlinX Serialization](https://github.com/Kotlin/kotlinx.serializat
|
||||
</Tabs>
|
||||
```kotlin
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
//Already the default serializer
|
||||
//Already the default serializer, but you can provide a custom Json instance (optional):
|
||||
defaultSerializer = KotlinXSerializer(Json {
|
||||
//apply your custom config
|
||||
})
|
||||
}
|
||||
```
|
||||
</RefSubLayout.Examples>
|
||||
|
||||
@@ -18,6 +18,8 @@ This reference documents every object and method available in Supabase's Kotlin
|
||||
|
||||
To see supported Kotlin targets, check the corresponding module README on [GitHub](https://github.com/supabase-community/supabase-kt).
|
||||
|
||||
To migrate from version 1.4.X to 2.0.0, see the [migration guide](https://github.com/supabase-community/supabase-kt/blob/master/MIGRATION.md)
|
||||
|
||||
</div>
|
||||
|
||||
<div className="max-w-xl bg-slate-300 px-4 py-2 rounded-md">
|
||||
|
||||
@@ -12,7 +12,7 @@ const clientLibFiles = [
|
||||
{ fileName: 'supabase_py_v2', label: 'python', version: 'v2', versionSlug: false },
|
||||
{ fileName: 'supabase_csharp_v0', label: 'csharp', version: 'v0', versionSlug: false },
|
||||
{ fileName: 'supabase_swift_v1', label: 'swift', version: 'v1', versionSlug: false },
|
||||
{ fileName: 'supabase_kt_v1', label: 'kotlin', version: 'v0', versionSlug: false },
|
||||
{ fileName: 'supabase_kt_v2', label: 'kotlin', version: 'v2', versionSlug: false },
|
||||
]
|
||||
|
||||
export function generateReferencePages() {
|
||||
|
||||
@@ -102,9 +102,13 @@ const levelsData = {
|
||||
icon: '/docs/img/icons/menu/reference-swift',
|
||||
name: 'Swift Reference v1.0',
|
||||
},
|
||||
reference_kotlin_v0: {
|
||||
reference_kotlin_v1: {
|
||||
icon: '/docs/img/icons/menu/reference-kotlin',
|
||||
name: 'Kotlin Reference v0.0',
|
||||
name: 'Kotlin Reference v1.0',
|
||||
},
|
||||
reference_kotlin_v2: {
|
||||
icon: '/docs/img/icons/menu/reference-kotlin',
|
||||
name: 'Kotlin Reference v2.0',
|
||||
},
|
||||
reference_cli: {
|
||||
icon: '/docs/img/icons/menu/reference-cli',
|
||||
|
||||
@@ -65,7 +65,7 @@ To sign up the user, call [signUpWith(Email)](/docs/reference/kotlin/auth-signup
|
||||
|
||||
```kotlin
|
||||
suspend fun signUpNewUser() {
|
||||
supabase.gotrue.signUpWith(Email) {
|
||||
supabase.auth.signUpWith(Email) {
|
||||
email = "example@email.com"
|
||||
password = "example-password"
|
||||
}
|
||||
@@ -110,7 +110,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun logout() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -156,11 +156,11 @@ Future<void> signInWithEmail() async {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Email)](/docs/reference/kotlin/auth-signinwithpassword) with their email address and password:
|
||||
When your user signs in, call [signInWith(Email)](/docs/reference/kotlin/auth-signinwithpassword) with their email address and password:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithEmail() {
|
||||
supabase.gotrue.loginWith(Email) {
|
||||
supabase.auth.signInWith(Email) {
|
||||
email = "example@email.com"
|
||||
password = "example-password"
|
||||
}
|
||||
@@ -208,7 +208,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun logout() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ await supabase.auth.resetPasswordForEmail('hello@example.com', {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
Supabase provides a convenient method [`.sendRecoveryEmail`](/docs/reference/kotlin/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectUrl` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user.
|
||||
Supabase provides a convenient method [`.resetPasswordForEmail`](/docs/reference/kotlin/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectUrl` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user.
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.sendRecoveryEmail(
|
||||
supabase.auth.resetPasswordForEmail(
|
||||
email = "hello@example.com",
|
||||
redirectUrl = "http://example.com/account/update-password"
|
||||
)
|
||||
@@ -76,7 +76,7 @@ await supabase.auth.updateUser({ password: new_password })
|
||||
To update the password we call the [`.modifyUser`](/docs/reference/kotlin/auth-updateuser) method and pass along the new password to this method.
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.modifyUser {
|
||||
supabase.auth.modifyUser {
|
||||
password = "new_password"
|
||||
}
|
||||
```
|
||||
@@ -114,10 +114,10 @@ We are using `next` as our query parameter, but this can name whatever you like.
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
Supabase provides a convenient method [`.sendRecoveryEmail`](/docs/reference/kotlin/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectUrl` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user.
|
||||
Supabase provides a convenient method [`.resetPasswordForEmail`](/docs/reference/kotlin/auth-resetpasswordforemail) to reset a user password. This method takes a parameter of `redirectUrl` which we will use to pass an absolute URL to the update password page. This URL must be saved in your allowed [Redirect URLs](https://supabase.com/dashboard/project/_/auth/url-configuration) list found at [Authentication > Redirect Configuration](https://supabase.com/dashboard/project/_/auth/url-configuration) or it won't redirect the user.
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.sendRecoveryEmail(
|
||||
supabase.auth.resetPasswordForEmail(
|
||||
email = "hello@example.com",
|
||||
redirectUrl = "http://example.com/api/auth/callback?next=/account/update-password"
|
||||
)
|
||||
@@ -237,7 +237,7 @@ await supabase.auth.updateUser({ password: new_password })
|
||||
To update the password we call the [`.modifyUser`](/docs/reference/kotlin/auth-updateuser) method and pass along the new password to this method.
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.modifyUser {
|
||||
supabase.auth.modifyUser {
|
||||
password = "new_password"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,14 +114,14 @@ const { data: profile } = await supabase
|
||||
|
||||
```kotlin
|
||||
// This will return nothing while the user is logged out
|
||||
val data = supabase.postgrest["profiles"].select(Columns.list("id", "username", "avatar_url", "website"))
|
||||
val data = supabase.from("profiles").select(Columns.list("id", "username", "avatar_url", "website"))
|
||||
|
||||
// After the user is logged in, this will only return
|
||||
// the logged-in user's data - in this case a single row
|
||||
supabase.gotrue.sendOtpTo(Email) {
|
||||
supabase.auth.signInWith(OTP) {
|
||||
this.email = email
|
||||
}
|
||||
val data = supabase.postgrest["profiles"].select(Columns.list("id", "username", "avatar_url", "website"))
|
||||
val data = supabase.from("profiles").select(Columns.list("id", "username", "avatar_url", "website"))
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -169,7 +169,7 @@ const { data, error } = await supabase.auth.signUp({
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val data = supabase.gotrue.signUpWith(Email) {
|
||||
val data = supabase.auth.signUpWith(Email) {
|
||||
email = "example@email.com"
|
||||
password = "example-password"
|
||||
data = buildJsonObject {
|
||||
@@ -204,9 +204,9 @@ let metadata = user.user_metadata
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val user = supabase.gotrue.retrieveUserForCurrentSession()
|
||||
val user = supabase.auth.retrieveUserForCurrentSession()
|
||||
//Or you can use the user from the current session:
|
||||
val user = supabase.gotrue.currentUserOrNull()
|
||||
val user = supabase.auth.currentUserOrNull()
|
||||
val metadata = user?.userMetadata
|
||||
```
|
||||
|
||||
|
||||
@@ -59,11 +59,11 @@ Future<void> signInWithEmailOtp() async {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [sendOtpTo()](/docs/reference/kotlin/auth-signinwithotp) with their email address:
|
||||
When your user signs in, call [signInWith(OTP)](/docs/reference/kotlin/auth-signinwithotp) with their email address:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithEmailOtp() {
|
||||
supabase.gotrue.sendOtpTo(Email) {
|
||||
supabase.auth.signInWith(OTP) {
|
||||
email = "example@email.com"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ Read the [Deep Linking Documentation](/docs/guides/auth/native-mobile-deep-linki
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
To start the sign in process call [signIn()](/docs/reference/dart/auth-signinwithotp) with their email address:
|
||||
When your user signs in, call [signIn()](/docs/reference/dart/auth-signinwithotp) with their email address:
|
||||
|
||||
```dart
|
||||
Future<void> signInWithEmail() async {
|
||||
@@ -81,11 +81,11 @@ Future<void> signInWithEmail() async {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
To start the sign in process call [sendOtpTo()](/docs/reference/kotlin/auth-signinwithotp) with their email address:
|
||||
To start the sign in process call [signInWith(OTP)](/docs/reference/kotlin/auth-signinwithotp) with their email address:
|
||||
|
||||
```kotlin
|
||||
suspend fun loginWithEmail() {
|
||||
supabase.gotrue.sendOtpTo(Email) {
|
||||
suspend fun signInWithEmail() {
|
||||
supabase.auth.signInWith(OTP) {
|
||||
email = "example@email.com"
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun logout() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -105,8 +105,8 @@ const {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.signUpWith(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signUpWith(Phone) {
|
||||
phone = "+13334445555"
|
||||
password = "some-password"
|
||||
}
|
||||
```
|
||||
@@ -156,9 +156,9 @@ const {
|
||||
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyPhoneOtp`:
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.verifyPhoneOtp(
|
||||
supabase.auth.verifyPhoneOtp(
|
||||
type = OtpType.Phone.SMS,
|
||||
phoneNumber = "+13334445555",
|
||||
phone = "+13334445555",
|
||||
token = "123456"
|
||||
)
|
||||
```
|
||||
@@ -215,8 +215,8 @@ const { user, error } = await supabase.auth.signInWithPassword({
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.loginWith(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signInWith(Phone) {
|
||||
phone = "+13334445555"
|
||||
password = "some-password"
|
||||
}
|
||||
```
|
||||
@@ -261,11 +261,11 @@ const { data, error } = await supabase.auth.signInWithOtp({
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
In Kotlin, we can use the `sendOtpTo` method and change the property `phoneNumber`
|
||||
In Kotlin, we can use the `signInWith(OTP)` method and change the property `phone`
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.sendOtpTo(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signInWith(OTP) {
|
||||
phone = "+13334445555"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -309,9 +309,9 @@ const {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.verifyPhoneOtp(
|
||||
supabase.auth.verifyPhoneOtp(
|
||||
type = OtpType.Phone.SMS,
|
||||
phoneNumber = "+13334445555",
|
||||
phone = "+13334445555",
|
||||
token = "123456"
|
||||
)
|
||||
```
|
||||
|
||||
@@ -159,8 +159,8 @@ const {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.signUpWith(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signUpWith(Phone) {
|
||||
phone = "+13334445555"
|
||||
password = "some-password"
|
||||
}
|
||||
```
|
||||
@@ -211,9 +211,9 @@ const {
|
||||
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyPhoneOtp`:
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.verifyPhoneOtp(
|
||||
supabase.auth.verifyPhoneOtp(
|
||||
type = OtpType.Phone.SMS,
|
||||
phoneNumber = "+13334445555",
|
||||
phone = "+13334445555",
|
||||
token = "123456"
|
||||
)
|
||||
```
|
||||
@@ -270,8 +270,8 @@ const { user, error } = await supabase.auth.signInWithPassword({
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.loginWith(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signInWith(Phone) {
|
||||
phone = "+13334445555"
|
||||
password = "some-password"
|
||||
}
|
||||
```
|
||||
@@ -316,11 +316,11 @@ const { data, error } = await supabase.auth.signInWithOtp({
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
In Kotlin, we can use the `sendOtpTo` method and change the property `phoneNumber`
|
||||
In Kotlin, we can use the `signInWith(OTP)` method and change the property `phone`
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.sendOtpTo(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signInWith(OTP) {
|
||||
phone = "+13334445555"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -365,9 +365,9 @@ const {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.verifyPhoneOtp(
|
||||
supabase.auth.verifyPhoneOtp(
|
||||
type = OtpType.Phone.SMS,
|
||||
phoneNumber = "+13334445555",
|
||||
phone = "+13334445555",
|
||||
token = "123456"
|
||||
)
|
||||
```
|
||||
|
||||
@@ -100,8 +100,8 @@ const {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.signUpWith(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signUpWith(Phone) {
|
||||
phone = "+13334445555"
|
||||
password = "some-password"
|
||||
}
|
||||
```
|
||||
@@ -151,9 +151,9 @@ const {
|
||||
You should present a form to the user so they can input the 6 digit pin, then send it along with the phone number to `verifyPhoneOtp`:
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.verifyPhoneOtp(
|
||||
supabase.auth.verifyPhoneOtp(
|
||||
type = OtpType.Phone.SMS,
|
||||
phoneNumber = "+13334445555",
|
||||
phone = "+13334445555",
|
||||
token = "123456"
|
||||
)
|
||||
```
|
||||
@@ -210,8 +210,8 @@ const { user, error } = await supabase.auth.signInWithPassword({
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.loginWith(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signInWith(Phone) {
|
||||
phone = "+13334445555"
|
||||
password = "some-password"
|
||||
}
|
||||
```
|
||||
@@ -256,11 +256,11 @@ const { data, error } = await supabase.auth.signInWithOtp({
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
In Kotlin, we can use the `sendOtpTo` method and change the property `phoneNumber`
|
||||
In Kotlin, we can use the `signInWith(OTP)` method and change the property `phone`
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.sendOtpTo(Phone) {
|
||||
phoneNumber = "+13334445555"
|
||||
supabase.auth.signInWith(OTP) {
|
||||
phone = "+13334445555"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -304,9 +304,9 @@ const {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.verifyPhoneOtp(
|
||||
supabase.auth.verifyPhoneOtp(
|
||||
type = OtpType.Phone.SMS,
|
||||
phoneNumber = "+13334445555",
|
||||
phone = "+13334445555",
|
||||
token = "123456"
|
||||
)
|
||||
```
|
||||
|
||||
@@ -315,7 +315,7 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
|
||||
|
||||
## Using Native Sign in with Apple in Kotlin
|
||||
|
||||
When using [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On iOS it uses Native Apple Login automatically and on other platforms it uses `gotrue.loginWith(Apple)`.
|
||||
When using [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On iOS it uses Native Apple Login automatically and on other platforms it uses `gotrue.signInWith(Apple)`.
|
||||
|
||||
**Initialize the Supabase Client**
|
||||
|
||||
|
||||
@@ -140,11 +140,11 @@ async function signInWithAzure() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Azure` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Azure` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithAzure() {
|
||||
supabase.gotrue.loginWith(Azure) {
|
||||
supabase.auth.signInWith(Azure) {
|
||||
scopes.add("email")
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -213,7 +213,7 @@ async function signInWithAzure() {
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithAzure() {
|
||||
supabase.gotrue.loginWith(Azure) {
|
||||
supabase.auth.signInWith(Azure) {
|
||||
scopes.add("offline_access")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +70,11 @@ async function signInWithBitbucket() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Bitbucket` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Bitbucket` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithBitbucket() {
|
||||
supabase.gotrue.loginWith(Bitbucket)
|
||||
supabase.auth.signInWith(Bitbucket)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -105,7 +105,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@ async function signInWithDiscord() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Discord` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Discord` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithDiscord() {
|
||||
supabase.gotrue.loginWith(Discord)
|
||||
supabase.auth.signInWith(Discord)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -106,7 +106,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -86,11 +86,11 @@ async function signInWithFacebook() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Facebook` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Facebook` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithFacebook() {
|
||||
supabase.gotrue.loginWith(Facebook)
|
||||
supabase.auth.signInWith(Facebook)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -121,7 +121,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -70,11 +70,11 @@ async function signInWithFigma() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Figma` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Figma` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithFigma() {
|
||||
supabase.gotrue.loginWith(Figma)
|
||||
supabase.auth.signInWith(Figma)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -105,7 +105,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -81,11 +81,11 @@ async function signInWithGithub() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Github` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Github` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithGithub() {
|
||||
supabase.gotrue.loginWith(Github)
|
||||
supabase.auth.signInWith(Github)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -116,7 +116,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -67,11 +67,11 @@ async function signInWithGitLab() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Gitlab` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Gitlab` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithGitLab() {
|
||||
supabase.gotrue.loginWith(Gitlab)
|
||||
supabase.auth.signInWith(Gitlab)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -102,7 +102,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ Before you can use Sign in with Google, you need to obtain a [Google Cloud Platf
|
||||
|
||||
When the user provides consent, Google issues an identity token (commonly abbreviated as ID token) that is then sent to your project's Supabase Auth server. When valid, a new user session is started by issuing an access and refresh token from Supabase Auth.
|
||||
|
||||
When using [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On Android it uses Google OneTap automatically and on other platforms it uses `gotrue.loginWith(Google)`.
|
||||
When using [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/), you can use the [compose-auth](https://supabase.com/docs/reference/kotlin/installing) plugin. On Android it uses Google OneTap (or Credential Manager on Android 14+) automatically and on other platforms it uses `auth.signInWith(Google)`.
|
||||
Alternatively, you can have a look at [Google One Tap](https://developers.google.com/identity/one-tap/android/overview), just login with the IdToken after you receive it.
|
||||
|
||||
**Initialize the Supabase Client**
|
||||
|
||||
@@ -92,11 +92,11 @@ async function signInWithKakao() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Kakao` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Kakao` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithKakao() {
|
||||
supabase.gotrue.loginWith(Kakao)
|
||||
supabase.auth.signInWith(Kakao)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -127,7 +127,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -86,11 +86,11 @@ async function signInWithKeycloak() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Keycloak` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Keycloak` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithKeycloak() {
|
||||
supabase.gotrue.loginWith(Keycloak) {
|
||||
supabase.auth.signInWith(Keycloak) {
|
||||
scopes.add("openid")
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -78,11 +78,11 @@ async function signInWithLinkedIn() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `LinkedIn` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `LinkedIn` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithKaLinkedIn() {
|
||||
supabase.gotrue.loginWith(LinkedIn)
|
||||
supabase.auth.signInWith(LinkedIn)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -113,7 +113,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -70,11 +70,11 @@ async function signInWithNotion() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Notion` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Notion` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithNotion() {
|
||||
supabase.gotrue.loginWith(Notion)
|
||||
supabase.auth.signInWith(Notion)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -105,7 +105,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -88,11 +88,11 @@ async function signInWithSlack() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Slack` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Slack` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithSlack() {
|
||||
supabase.gotrue.loginWith(Slack)
|
||||
supabase.auth.signInWith(Slack)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -123,7 +123,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -74,11 +74,11 @@ async function signInWithSpotify() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Spotify` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Spotify` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithSpotify() {
|
||||
supabase.gotrue.loginWith(Spotify)
|
||||
supabase.auth.signInWith(Spotify)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -109,7 +109,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -85,11 +85,11 @@ async function signInWithTwitch() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Twitch` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Twitch` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithTwitch() {
|
||||
supabase.gotrue.loginWith(Twitch)
|
||||
supabase.auth.signInWith(Twitch)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -120,7 +120,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -76,11 +76,11 @@ async function signInWithTwitter() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Twitter` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Twitter` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithTwitter() {
|
||||
supabase.gotrue.loginWith(Twitter)
|
||||
supabase.auth.signInWith(Twitter)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -111,7 +111,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -83,11 +83,11 @@ Refer to the [WorkOS Documentation](https://workos.com/docs/reference/sso/author
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `WorkOS` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `WorkOS` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithWorkOS() {
|
||||
supabase.gotrue.loginWith(WorkOS) {
|
||||
supabase.auth.signInWith(WorkOS) {
|
||||
queryParams["connection"] = "<your_connection>"
|
||||
queryParams["organization"] = "<your_organization>"
|
||||
queryParams["workos_provider"] = "<your_provider>"
|
||||
@@ -124,7 +124,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -83,11 +83,11 @@ async function signInWithZoom() {
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
When your user signs in, call [loginWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Zoom` as the `Provider`:
|
||||
When your user signs in, call [signInWith(Provider)](/docs/reference/kotlin/auth-signinwithoauth) with `Zoom` as the `Provider`:
|
||||
|
||||
```kotlin
|
||||
suspend fun signInWithZoom() {
|
||||
supabase.gotrue.loginWith(Zoom)
|
||||
supabase.auth.signInWith(Zoom)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -118,7 +118,7 @@ When your user signs out, call [logout()](/docs/reference/kotlin/auth-signout) t
|
||||
|
||||
```kotlin
|
||||
suspend fun signOut() {
|
||||
supabase.gotrue.logout()
|
||||
supabase.auth.signOut()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -208,10 +208,12 @@ Calling [`signInWithSSO`](/docs/reference/javascript/auth-signinwithsso) starts
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
supabase.gotrue.loginWith(SSO.withDomain("company.com"))
|
||||
supabase.auth.signInWith(SSO) {
|
||||
domain = "company.com"
|
||||
}
|
||||
```
|
||||
|
||||
Calling [`loginWith(SSO)`](/docs/reference/kotlin/auth-signinwithsso) starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
|
||||
Calling [`signInWith(SSO)`](/docs/reference/kotlin/auth-signinwithsso) starts the sign-in process using the identity provider registered for the `company.com` domain name. It is not required that identity providers be assigned one or multiple domain names, in which case you can use the provider's unique ID instead.
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
@@ -21,22 +21,17 @@ export const meta = {
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```sql SQL_EDITOR
|
||||
-- Create products table
|
||||
create table
|
||||
public.products (
|
||||
_id bigint generated by default as identity not null,
|
||||
productid text not null,
|
||||
name text null,
|
||||
description text null,
|
||||
price real null,
|
||||
image text null,
|
||||
category text null,
|
||||
nutrition text null,
|
||||
constraint products_pkey primary key (productid),
|
||||
) tablespace pg_default;
|
||||
|
||||
````
|
||||
```sql SQL_EDITOR
|
||||
-- Create the table
|
||||
CREATE TABLE countries (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL
|
||||
);
|
||||
-- Insert some sample data into the table
|
||||
INSERT INTO countries (name) VALUES ('United States');
|
||||
INSERT INTO countries (name) VALUES ('Canada');
|
||||
INSERT INTO countries (name) VALUES ('Mexico');
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
@@ -53,15 +48,28 @@ export const meta = {
|
||||
|
||||
<StepHikeCompact.Step step={3}>
|
||||
|
||||
<StepHikeCompact.Details title="Install the Supabase client library">
|
||||
Import Supabase and all required dependencies. Replace the version placeholders `$supabase_version` and `$ktor_version` with the respective latest versions.
|
||||
<StepHikeCompact.Details title="Install the Dependencies">
|
||||
Open `build.gradle.kts` (app) file and add the serialization plug, Ktor client, and Supabase client.
|
||||
|
||||
Replace the version placeholders `$kotlin_version` with the Kotlin version of the project, and `$supabase_version` and `$ktor_version` with the respective latest versions.
|
||||
|
||||
The latest supabase-kt version can be found [here](https://github.com/supabase-community/supabase-kt/releases) and Ktor version can be found [here](https://ktor.io/docs/welcome.html).
|
||||
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
implementation "io.github.jan-tennert.supabase:postgrest-kt:$supabase_version"
|
||||
implementation "io.ktor:ktor-client-android:$ktor_version"
|
||||
plugins {
|
||||
...
|
||||
kotlin("plugin.serialization") version "$kotlin_version"
|
||||
}
|
||||
...
|
||||
dependencies {
|
||||
...
|
||||
implementation(platform("io.github.jan-tennert.supabase:bom:$supabase_version"))
|
||||
implementation("io.github.jan-tennert.supabase:postgrest-kt")
|
||||
implementation("io.ktor:ktor-client-android:$ktor_version")
|
||||
}
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
@@ -70,17 +78,15 @@ export const meta = {
|
||||
|
||||
<StepHikeCompact.Step step={4}>
|
||||
|
||||
<StepHikeCompact.Details title="Install the serializable plugin">
|
||||
Open the `build.gradle` (app), add the serialization plugin to use annotation for data parsing. Please note that the plugin version should be the same as the Kotlin version in your app.
|
||||
<StepHikeCompact.Details title="Add internet access permission">
|
||||
Add the following line to the `AndroidManifest.xml` file under the `manifest` tag and outside the `application` tag.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
plugins {
|
||||
...
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version '$kotlin_version'
|
||||
...
|
||||
}
|
||||
```xml
|
||||
...
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
...
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
@@ -90,18 +96,25 @@ export const meta = {
|
||||
<StepHikeCompact.Step step={5}>
|
||||
|
||||
<StepHikeCompact.Details title="Initialize the Supabase client">
|
||||
You can create a Supabase client whenever you need to perform an API call. That being said, it is recommended to use a dependency injection library like [Hilt](https://developer.android.com/training/dependency-injection/hilt-android#kts).
|
||||
You can create a Supabase client whenever you need to perform an API call.
|
||||
|
||||
For the sake of simplicity, we will create a client in the `MainActivity.kt` file at the top just below the imports.
|
||||
|
||||
Replace the `supabaseUrl` and `supabaseKey` with your own found in [your dashboard](https://supabase.com/dashboard/project/_/settings/api).
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```kotlin
|
||||
val client = createSupabaseClient(
|
||||
import ...
|
||||
|
||||
val supabase = createSupabaseClient(
|
||||
supabaseUrl = "https://xyzcompany.supabase.co",
|
||||
supabaseKey = "public-anon-key"
|
||||
supabaseKey = "your_public_anon_key"
|
||||
) {
|
||||
install(Postgrest)
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
@@ -110,29 +123,18 @@ export const meta = {
|
||||
|
||||
<StepHikeCompact.Step step={6}>
|
||||
|
||||
<StepHikeCompact.Details title="Create a data transfer object">
|
||||
<StepHikeCompact.Details title="Create a data model for countries">
|
||||
Create a serializable data class to represent the data from the database.
|
||||
|
||||
Add the following below the `createSupabaseClient` function in the `MainActivity.kt` file.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
@Serializable
|
||||
data class ProductDto(
|
||||
@SerialName("productid")
|
||||
val productId: String,
|
||||
@SerialName("name")
|
||||
data class Country(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
@SerialName("description")
|
||||
val description: String,
|
||||
@SerialName("price")
|
||||
val price: Double,
|
||||
@SerialName("image")
|
||||
val image: String,
|
||||
@SerialName("category")
|
||||
val category: String,
|
||||
@SerialName("nutrition")
|
||||
val nutrition: String,
|
||||
@SerialName("_id")
|
||||
val _id: Int,
|
||||
)
|
||||
```
|
||||
|
||||
@@ -142,48 +144,52 @@ export const meta = {
|
||||
|
||||
<StepHikeCompact.Step step={7}>
|
||||
|
||||
<StepHikeCompact.Details title="Create a domain object">
|
||||
This kind of object will be consumed by the view.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
data class Product(
|
||||
val productId: String,
|
||||
val name: String,
|
||||
val description: String,
|
||||
val price: Double,
|
||||
val image: String,
|
||||
val category: String,
|
||||
val nutrition: String,
|
||||
val _id: Int,
|
||||
)
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={8}>
|
||||
|
||||
<StepHikeCompact.Details title="Query data from the app">
|
||||
Create a repository to interact with the data source.
|
||||
Use `LaunchedEffect` to fetch data from the database and display it in a `LazyColumn`.
|
||||
|
||||
Replace the default `MainActivity` class with the following code.
|
||||
|
||||
Note that we are making a network request from our UI code. In production, you should probably use a `ViewModel` to separate the UI and data fetching logic.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
interface ProductRepository {
|
||||
fun getProducts(): List<ProductDto>
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
SupabaseTutorialTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
CountriesList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ProductRepositoryImpl @Inject constructor(
|
||||
private val postgrest: Postgrest,
|
||||
) : ProductRepository {
|
||||
override suspend fun getProducts(): List<ProductDto> {
|
||||
val result = client.postgrest["products"]
|
||||
.select().decodeList<ProductDto>()
|
||||
// Handle result data for next step
|
||||
return result
|
||||
@Composable
|
||||
fun CountriesList() {
|
||||
var countries by remember { mutableStateOf<List<Country>>(listOf()) }
|
||||
LaunchedEffect(Unit) {
|
||||
withContext(Dispatchers.IO) {
|
||||
countries = supabase.from("countries")
|
||||
.select().decodeList<Country>()
|
||||
}
|
||||
}
|
||||
LazyColumn {
|
||||
items(
|
||||
countries,
|
||||
key = { country -> country.id },
|
||||
) { country ->
|
||||
Text(
|
||||
country.name,
|
||||
modifier = Modifier.padding(8.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -191,105 +197,9 @@ export const meta = {
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={9}>
|
||||
<StepHikeCompact.Details title="Create a module to provide repository">
|
||||
Use [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) for dependency injection.
|
||||
</StepHikeCompact.Details>
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
abstract class RepositoryModule {
|
||||
@Binds
|
||||
abstract fun bindProductRepository(impl: ProductRepositoryImpl): ProductRepository
|
||||
}
|
||||
```
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={10}>
|
||||
<StepHikeCompact.Details title="Get data from ViewModel inside a coroutine scope">
|
||||
Add the `@Inject` annotation to use the repository in a ViewModel.
|
||||
</StepHikeCompact.Details>
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
class ProductListViewModel @Inject constructor(
|
||||
private val productRepository: ProductRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _productList = MutableStateFlow<List<Product>?>(listOf())
|
||||
val productList: Flow<List<Product>?> = _productList
|
||||
|
||||
init {
|
||||
getProducts()
|
||||
}
|
||||
|
||||
fun getProducts() {
|
||||
viewModelScope.launch {
|
||||
val products = productRepository.getProducts()
|
||||
_productList.emit(products?.map { it -> it.asDomainModel() })
|
||||
}
|
||||
}
|
||||
|
||||
private fun ProductDto.asDomainModel(): Product {
|
||||
return Product(
|
||||
productId = this.productId,
|
||||
name = this.name,
|
||||
price = this.price,
|
||||
image = this.image,
|
||||
description = this.description,
|
||||
category = this.category,
|
||||
nutrition = this.nutrition,
|
||||
_id = this._id
|
||||
)
|
||||
}
|
||||
```
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={11}>
|
||||
<StepHikeCompact.Details title="Observe data in a Composable">
|
||||
</StepHikeCompact.Details>
|
||||
<StepHikeCompact.Code>
|
||||
```kotlin
|
||||
@Composable
|
||||
fun ProductListScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
navController: NavController,
|
||||
viewModel: ProductListViewModel = hiltViewModel(),
|
||||
) {
|
||||
val productList = viewModel.productList.collectAsState(initial = listOf()).value
|
||||
if (!productList.isNullOrEmpty()) {
|
||||
LazyColumn(
|
||||
modifier = modifier.padding(24.dp),
|
||||
contentPadding = PaddingValues(5.dp)
|
||||
) {
|
||||
items(productList) { item ->
|
||||
ProductListItem(
|
||||
product = item,
|
||||
modifier = modifier,
|
||||
onClick = {
|
||||
navController.navigate(
|
||||
ProductDetailsDestination.createRouteWithParam(
|
||||
item.id
|
||||
)
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</StepHikeCompact.Code>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
<StepHikeCompact.Step step={12}>
|
||||
<StepHikeCompact.Step step={8}>
|
||||
<StepHikeCompact.Details title="Start the app">
|
||||
|
||||
Run the app on an emulator or a physical device by clicking the `Run app` button in Android Studio.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
</StepHikeCompact.Step>
|
||||
|
||||
@@ -127,11 +127,12 @@ Open the `AndroidManifest.xml` file, update name property of Application tag:
|
||||
|
||||
```
|
||||
|
||||
Add annotation for the `MainActivity`:
|
||||
Create the `MainActivity`:
|
||||
|
||||
```kotlin
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
//This will come later
|
||||
}
|
||||
```
|
||||
|
||||
@@ -152,7 +153,7 @@ object SupabaseModule {
|
||||
supabaseKey = BuildConfig.SUPABASE_ANON_KEY
|
||||
) {
|
||||
install(Postgrest)
|
||||
install(GoTrue) {
|
||||
install(Auth) {
|
||||
flowType = FlowType.PKCE
|
||||
scheme = "app"
|
||||
host = "supabase.com"
|
||||
@@ -169,8 +170,8 @@ object SupabaseModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSupabaseGoTrue(client: SupabaseClient): GoTrue {
|
||||
return client.gotrue
|
||||
fun provideSupabaseAuth(client: SupabaseClient): Auth {
|
||||
return client.auth
|
||||
}
|
||||
|
||||
|
||||
@@ -246,7 +247,7 @@ class ProductRepositoryImpl @Inject constructor(
|
||||
name = product.name,
|
||||
price = product.price,
|
||||
)
|
||||
postgrest["products"].insert(productDto)
|
||||
postgrest.from("products").insert(productDto)
|
||||
true
|
||||
}
|
||||
true
|
||||
@@ -257,7 +258,7 @@ class ProductRepositoryImpl @Inject constructor(
|
||||
|
||||
override suspend fun getProducts(): List<ProductDto>? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val result = postgrest["products"]
|
||||
val result = postgrest.from("products")
|
||||
.select().decodeList<ProductDto>()
|
||||
result
|
||||
}
|
||||
@@ -266,7 +267,7 @@ class ProductRepositoryImpl @Inject constructor(
|
||||
|
||||
override suspend fun getProduct(id: String): ProductDto {
|
||||
return withContext(Dispatchers.IO) {
|
||||
postgrest["products"].select {
|
||||
postgrest.from("products").select {
|
||||
eq("id", id)
|
||||
}.decodeSingle<ProductDto>()
|
||||
}
|
||||
@@ -274,7 +275,7 @@ class ProductRepositoryImpl @Inject constructor(
|
||||
|
||||
override suspend fun deleteProduct(id: String) {
|
||||
return withContext(Dispatchers.IO) {
|
||||
postgrest["products"].delete {
|
||||
postgrest.from("products").delete {
|
||||
eq("id", id)
|
||||
}
|
||||
}
|
||||
@@ -290,12 +291,12 @@ class ProductRepositoryImpl @Inject constructor(
|
||||
withContext(Dispatchers.IO) {
|
||||
if (imageFile.isNotEmpty()) {
|
||||
val imageUrl =
|
||||
storage["Product%20Image"].upload(
|
||||
storage.from("Product%20Image").upload(
|
||||
path = "$imageName.png",
|
||||
data = imageFile,
|
||||
upsert = true
|
||||
)
|
||||
postgrest["products"].update({
|
||||
postgrest.from("products").update({
|
||||
set("name", name)
|
||||
set("price", price)
|
||||
set("image", buildImageUrl(imageFileName = imageUrl))
|
||||
@@ -303,7 +304,7 @@ class ProductRepositoryImpl @Inject constructor(
|
||||
eq("id", id)
|
||||
}
|
||||
} else {
|
||||
postgrest["products"].update({
|
||||
postgrest.from("products").update({
|
||||
set("name", name)
|
||||
set("price", price)
|
||||
}) {
|
||||
@@ -332,11 +333,11 @@ interface AuthenticationRepository {
|
||||
|
||||
```kotlin
|
||||
class AuthenticationRepositoryImpl @Inject constructor(
|
||||
private val goTrue: GoTrue
|
||||
private val auth: Auth
|
||||
) : AuthenticationRepository {
|
||||
override suspend fun signIn(email: String, password: String): Boolean {
|
||||
return try {
|
||||
goTrue.loginWith(Email) {
|
||||
auth.signInWith(Email) {
|
||||
this.email = email
|
||||
this.password = password
|
||||
}
|
||||
@@ -348,7 +349,7 @@ class AuthenticationRepositoryImpl @Inject constructor(
|
||||
|
||||
override suspend fun signUp(email: String, password: String): Boolean {
|
||||
return try {
|
||||
goTrue.signUpWith(Email) {
|
||||
auth.signUpWith(Email) {
|
||||
this.email = email
|
||||
this.password = password
|
||||
}
|
||||
@@ -360,7 +361,7 @@ class AuthenticationRepositoryImpl @Inject constructor(
|
||||
|
||||
override suspend fun signInWithGoogle(): Boolean {
|
||||
return try {
|
||||
goTrue.loginWith(Google)
|
||||
auth.signInWith(Google)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
@@ -371,6 +372,49 @@ class AuthenticationRepositoryImpl @Inject constructor(
|
||||
|
||||
### Implement screens
|
||||
|
||||
To navigate screens, use the AndroidX navigation library. For routes, implement a `Destination` interface:
|
||||
|
||||
```kotlin
|
||||
|
||||
interface Destination {
|
||||
val route: String
|
||||
val title: String
|
||||
}
|
||||
|
||||
|
||||
object ProductListDestination : Destination {
|
||||
override val route = "product_list"
|
||||
override val title = "Product List"
|
||||
}
|
||||
|
||||
object ProductDetailsDestination : Destination {
|
||||
override val route = "product_details"
|
||||
override val title = "Product Details"
|
||||
const val productId = "product_id"
|
||||
val arguments = listOf(navArgument(name = productId) {
|
||||
type = NavType.StringType
|
||||
})
|
||||
fun createRouteWithParam(productId: String) = "$route/${productId}"
|
||||
}
|
||||
|
||||
object AddProductDestination : Destination {
|
||||
override val route = "add_product"
|
||||
override val title = "Add Product"
|
||||
}
|
||||
|
||||
object AuthenticationDestination: Destination {
|
||||
override val route = "authentication"
|
||||
override val title = "Authentication"
|
||||
}
|
||||
|
||||
object SignUpDestination: Destination {
|
||||
override val route = "signup"
|
||||
override val title = "Sign Up"
|
||||
}
|
||||
```
|
||||
|
||||
This will help later for navigating between screens.
|
||||
|
||||
Create a `ProductListViewModel`:
|
||||
|
||||
```kotlin
|
||||
@@ -1029,7 +1073,7 @@ class SignInViewModel @Inject constructor(
|
||||
_password.value = password
|
||||
}
|
||||
|
||||
fun onLogin() {
|
||||
fun onSignIn() {
|
||||
viewModelScope.launch {
|
||||
authenticationRepository.signIn(
|
||||
email = _email.value,
|
||||
@@ -1162,9 +1206,77 @@ fun SignInScreen(
|
||||
}
|
||||
```
|
||||
|
||||
### Implement the `MainActivity`
|
||||
|
||||
In the `MainActivity` you created earlier, show your newly created screens:
|
||||
|
||||
```kotlin
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
@Inject
|
||||
lateinit var supabaseClient: SupabaseClient
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
ManageProductsTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
val navController = rememberNavController()
|
||||
val currentBackStack by navController.currentBackStackEntryAsState()
|
||||
val currentDestination = currentBackStack?.destination
|
||||
Scaffold { innerPadding ->
|
||||
NavHost(
|
||||
navController,
|
||||
startDestination = ProductListDestination.route,
|
||||
Modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(ProductListDestination.route) {
|
||||
ProductListScreen(
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
|
||||
composable(AuthenticationDestination.route) {
|
||||
SignInScreen(
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
|
||||
composable(SignUpDestination.route) {
|
||||
SignUpScreen(
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
|
||||
composable(AddProductDestination.route) {
|
||||
AddProductScreen(
|
||||
navController = navController
|
||||
)
|
||||
}
|
||||
|
||||
composable(
|
||||
route = "${ProductDetailsDestination.route}/{${ProductDetailsDestination.productId}}",
|
||||
arguments = ProductDetailsDestination.arguments
|
||||
) { navBackStackEntry ->
|
||||
val productId =
|
||||
navBackStackEntry.arguments?.getString(ProductDetailsDestination.productId)
|
||||
ProductDetailsScreen(
|
||||
productId = productId,
|
||||
navController = navController,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Create the success screen
|
||||
|
||||
Implement a "Sign In" success screen. Create new "Empty Activity" and in `AndroidManifest.xml`, add a deep link, make sure `scheme` and `host` are the same as the ones set in the GoTrue instance.
|
||||
To handle OAuth and OTP signins, create a new activity to handle the deeplink you set in `AndroidManifest.xml`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
@@ -1209,6 +1321,8 @@ Implement a "Sign In" success screen. Create new "Empty Activity" and in `Androi
|
||||
</manifest>
|
||||
```
|
||||
|
||||
Then create the `DeepLinkHandlerActivity`:
|
||||
|
||||
```kotlin
|
||||
@AndroidEntryPoint
|
||||
class DeepLinkHandlerActivity : ComponentActivity() {
|
||||
|
||||
@@ -24,46 +24,46 @@ Go to your Supabase project's [API Settings](https://supabase.com/dashboard/proj
|
||||
defaultActiveId="js"
|
||||
queryGroup="language"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
```js
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const SUPABASE_URL = 'https://<project>.supabase.co'
|
||||
const SUPABASE_KEY = '<your-anon-key>'
|
||||
const SUPABASE_URL = 'https://<project>.supabase.co'
|
||||
const SUPABASE_KEY = '<your-anon-key>'
|
||||
|
||||
const client = createClient(SUPABASE_URL, SUPABASE_KEY)
|
||||
```
|
||||
const client = createClient(SUPABASE_URL, SUPABASE_KEY)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
```dart
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
void main() async {
|
||||
Supabase.initialize(
|
||||
url: 'https://<project>.supabase.co',
|
||||
anonKey: '<your-anon-key>',
|
||||
);
|
||||
runApp(MyApp());
|
||||
}
|
||||
void main() async {
|
||||
Supabase.initialize(
|
||||
url: 'https://<project>.supabase.co',
|
||||
anonKey: '<your-anon-key>',
|
||||
);
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
final supabase = Supabase.instance.client;
|
||||
```
|
||||
final supabase = Supabase.instance.client;
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val supabaseUrl = "https://<project>.supabase.co"
|
||||
val supabaseKey = "<your-anon-key>"
|
||||
val client = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
install(Realtime)
|
||||
}
|
||||
```
|
||||
```kotlin
|
||||
val supabaseUrl = "https://<project>.supabase.co"
|
||||
val supabaseKey = "<your-anon-key>"
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
install(Realtime)
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Listening to Broadcast messages
|
||||
@@ -77,62 +77,61 @@ You can provide a callback for the `broadcast` channel to receive message. In th
|
||||
defaultActiveId="js"
|
||||
queryGroup="language"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
// Join a room/topic. Can be anything except for 'realtime'.
|
||||
const channelA = clientA.channel('room-1')
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
// Join a room/topic. Can be anything except for 'realtime'.
|
||||
const channelA = clientA.channel('room-1')
|
||||
|
||||
// Simple function to log any messages we receive
|
||||
function messageReceived(payload) {
|
||||
console.log(payload)
|
||||
}
|
||||
|
||||
// Subscribe to the Channel
|
||||
channelA
|
||||
.on(
|
||||
'broadcast',
|
||||
{ event: 'test' },
|
||||
(payload) => messageReceived(payload)
|
||||
)
|
||||
.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
// Simple function to log any messages we receive
|
||||
void messageReceived(payload) {
|
||||
print(payload);
|
||||
}
|
||||
|
||||
// Subscribe to the Channel
|
||||
channelA
|
||||
.onBroadcast(
|
||||
event: 'test', callback: (payload) => messageReceived(payload))
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val channelA = clientA.realtime.createChannel("room-1")
|
||||
|
||||
//Listen for broadcast messages
|
||||
val broadcastFlow: Flow<JsonObject> = channelA.broadcastFlow<JsonObject>("test")
|
||||
.onEach {
|
||||
println(it)
|
||||
// Simple function to log any messages we receive
|
||||
function messageReceived(payload) {
|
||||
console.log(payload)
|
||||
}
|
||||
.launchIn(yourCoroutineScope) //you can also use .collect { } here
|
||||
|
||||
clientA.realtime.connect()
|
||||
channelA.join()
|
||||
```
|
||||
// Subscribe to the Channel
|
||||
channelA
|
||||
.on(
|
||||
'broadcast',
|
||||
{ event: 'test' },
|
||||
(payload) => messageReceived(payload)
|
||||
)
|
||||
.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
// Simple function to log any messages we receive
|
||||
void messageReceived(payload) {
|
||||
print(payload);
|
||||
}
|
||||
|
||||
// Subscribe to the Channel
|
||||
channelA
|
||||
.onBroadcast(
|
||||
event: 'test', callback: (payload) => messageReceived(payload))
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val channelA = clientA.channel("room-1")
|
||||
|
||||
//Listen for broadcast messages
|
||||
val broadcastFlow: Flow<JsonObject> = channelA.broadcastFlow<JsonObject>("test")
|
||||
.onEach {
|
||||
println(it)
|
||||
}
|
||||
.launchIn(yourCoroutineScope) //you can also use .collect { } here
|
||||
|
||||
channelA.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Sending Broadcast messages
|
||||
@@ -144,70 +143,68 @@ channelA.join()
|
||||
defaultActiveId="js"
|
||||
queryGroup="language"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
We can send Broadcast messages using `channelB.send()`. Let's set up another client to send messages.
|
||||
We can send Broadcast messages using `channelB.send()`. Let's set up another client to send messages.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
// Join a room/topic. Can be anything except for 'realtime'.
|
||||
const channelB = clientA.channel('room-1')
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
// Join a room/topic. Can be anything except for 'realtime'.
|
||||
const channelB = clientA.channel('room-1')
|
||||
|
||||
channelB.subscribe((status) => {
|
||||
// Wait for successful connection
|
||||
if (status !== 'SUBSCRIBED') {
|
||||
return null
|
||||
}
|
||||
channelB.subscribe((status) => {
|
||||
// Wait for successful connection
|
||||
if (status !== 'SUBSCRIBED') {
|
||||
return null
|
||||
}
|
||||
|
||||
// Send a message once the client is subscribed
|
||||
channelB.send({
|
||||
type: 'broadcast',
|
||||
event: 'test',
|
||||
payload: { message: 'hello, world' },
|
||||
})
|
||||
})
|
||||
```
|
||||
// Send a message once the client is subscribed
|
||||
channelB.send({
|
||||
type: 'broadcast',
|
||||
event: 'test',
|
||||
payload: { message: 'hello, world' },
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
// Join a room/topic. Can be anything except for 'realtime'.
|
||||
final channelB = supabase.channel('room-1');
|
||||
```dart
|
||||
// Join a room/topic. Can be anything except for 'realtime'.
|
||||
final channelB = supabase.channel('room-1');
|
||||
|
||||
channelB.subscribe((status, error) {
|
||||
// Wait for successful connection
|
||||
if (status != RealtimeSubscribeStatus.subscribed) {
|
||||
return;
|
||||
}
|
||||
channelB.subscribe((status, error) {
|
||||
// Wait for successful connection
|
||||
if (status != RealtimeSubscribeStatus.subscribed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a message once the client is subscribed
|
||||
channelB.sendBroadcastMessage(
|
||||
event: 'test',
|
||||
payload: {'message': 'hello, world'},
|
||||
);
|
||||
});
|
||||
```
|
||||
// Send a message once the client is subscribed
|
||||
channelB.sendBroadcastMessage(
|
||||
event: 'test',
|
||||
payload: {'message': 'hello, world'},
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
We can send Broadcast messages using `channelB.broadcast()`. Let's set up another client to send messages.
|
||||
We can send Broadcast messages using `channelB.broadcast()`. Let's set up another client to send messages.
|
||||
|
||||
```kotlin
|
||||
val channelB = clientA.realtime.createChannel("room-1")
|
||||
```kotlin
|
||||
val channelB = clientA.channel("room-1")
|
||||
|
||||
clientA.realtime.connect()
|
||||
channelB.subscribe(blockUntilSubscribed = true) //You can also use the channelA.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
|
||||
channelB.join(blockUntilJoined = true) //You can also use the channelA.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
channelB.broadcast(
|
||||
event = "test",
|
||||
payload = YourMessage(message = "hello, world!")
|
||||
)
|
||||
```
|
||||
|
||||
channelB.broadcast(
|
||||
event = "test",
|
||||
payload = YourMessage(message = "hello, world!")
|
||||
)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
Before sending messages we need to ensure the client is connected, which we have done within the `subscribe()` callback.
|
||||
@@ -225,90 +222,89 @@ You can pass configuration options while initializing the Supabase Client.
|
||||
defaultActiveId="js"
|
||||
queryGroup="language"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `self` parameter to `true`.
|
||||
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `self` parameter to `true`.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
const myChannel = supabase.channel('room-2', {
|
||||
config: {
|
||||
broadcast: { self: true },
|
||||
},
|
||||
})
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
const myChannel = supabase.channel('room-2', {
|
||||
config: {
|
||||
broadcast: { self: true },
|
||||
},
|
||||
})
|
||||
|
||||
myChannel.on(
|
||||
'broadcast',
|
||||
{ event: 'test-my-messages' },
|
||||
(payload) => console.log(payload)
|
||||
)
|
||||
|
||||
myChannel.subscribe((status) => {
|
||||
if (status !== 'SUBSCRIBED') { return }
|
||||
channelC.send({
|
||||
type: 'broadcast',
|
||||
event: 'test-my-messages',
|
||||
payload: { message: 'talking to myself' },
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
final myChannel = supabase.channel(
|
||||
'room-2',
|
||||
opts: const RealtimeChannelConfig(
|
||||
self: true,
|
||||
),
|
||||
);
|
||||
|
||||
myChannel.onBroadcast(
|
||||
event: 'test-my-messages',
|
||||
callback: (payload) => print(payload),
|
||||
);
|
||||
|
||||
myChannel.subscribe((status, error) {
|
||||
if (status != RealtimeSubscribeStatus.subscribed) return;
|
||||
// channelC.send({
|
||||
myChannel.sendBroadcastMessage(
|
||||
event: 'test-my-messages',
|
||||
payload: {'message': 'talking to myself'},
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `receiveOwnBroadcasts` parameter to `true`.
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("room-2") {
|
||||
broadcast {
|
||||
receiveOwnBroadcasts = true
|
||||
}
|
||||
}
|
||||
|
||||
val broadcastFlow: Flow<JsonObject> = myChannel.broadcastFlow<JsonObject>("test-my-messages")
|
||||
.onEach {
|
||||
println(it)
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
clientA.realtime.connect()
|
||||
myChannel.join(blockUntilJoined = true) //You can also use the myChannel.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
|
||||
myChannel.broadcast(
|
||||
event = "test-my-messages",
|
||||
payload = YourMessage(
|
||||
message = "talking to myself"
|
||||
myChannel.on(
|
||||
'broadcast',
|
||||
{ event: 'test-my-messages' },
|
||||
(payload) => console.log(payload)
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
myChannel.subscribe((status) => {
|
||||
if (status !== 'SUBSCRIBED') { return }
|
||||
channelC.send({
|
||||
type: 'broadcast',
|
||||
event: 'test-my-messages',
|
||||
payload: { message: 'talking to myself' },
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
final myChannel = supabase.channel(
|
||||
'room-2',
|
||||
opts: const RealtimeChannelConfig(
|
||||
self: true,
|
||||
),
|
||||
);
|
||||
|
||||
myChannel.onBroadcast(
|
||||
event: 'test-my-messages',
|
||||
callback: (payload) => print(payload),
|
||||
);
|
||||
|
||||
myChannel.subscribe((status, error) {
|
||||
if (status != RealtimeSubscribeStatus.subscribed) return;
|
||||
// channelC.send({
|
||||
myChannel.sendBroadcastMessage(
|
||||
event: 'test-my-messages',
|
||||
payload: {'message': 'talking to myself'},
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `receiveOwnBroadcasts` parameter to `true`.
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.channel("room-2") {
|
||||
broadcast {
|
||||
receiveOwnBroadcasts = true
|
||||
}
|
||||
}
|
||||
|
||||
val broadcastFlow: Flow<JsonObject> = myChannel.broadcastFlow<JsonObject>("test-my-messages")
|
||||
.onEach {
|
||||
println(it)
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
myChannel.subscribe(blockUntilSubscribed = true) //You can also use the myChannel.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
|
||||
myChannel.broadcast(
|
||||
event = "test-my-messages",
|
||||
payload = YourMessage(
|
||||
message = "talking to myself"
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
### Acknowledge messages
|
||||
@@ -320,73 +316,72 @@ myChannel.broadcast(
|
||||
defaultActiveId="js"
|
||||
queryGroup="language"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
|
||||
You can confirm that Realtime received your message by setting Broadcast's `ack` config to `true`.
|
||||
You can confirm that Realtime received your message by setting Broadcast's `ack` config to `true`.
|
||||
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
const myChannel = clientD.channel('room-3', {
|
||||
config: {
|
||||
broadcast: { ack: true },
|
||||
},
|
||||
})
|
||||
{/* prettier-ignore */}
|
||||
```js
|
||||
const myChannel = clientD.channel('room-3', {
|
||||
config: {
|
||||
broadcast: { ack: true },
|
||||
},
|
||||
})
|
||||
|
||||
myChannel.subscribe(async (status) => {
|
||||
if (status !== 'SUBSCRIBED') { return }
|
||||
myChannel.subscribe(async (status) => {
|
||||
if (status !== 'SUBSCRIBED') { return }
|
||||
|
||||
const serverResponse = await myChannel.send({
|
||||
type: 'broadcast',
|
||||
event: 'acknowledge',
|
||||
payload: {},
|
||||
})
|
||||
const serverResponse = await myChannel.send({
|
||||
type: 'broadcast',
|
||||
event: 'acknowledge',
|
||||
payload: {},
|
||||
})
|
||||
|
||||
console.log('serverResponse', serverResponse)
|
||||
})
|
||||
```
|
||||
console.log('serverResponse', serverResponse)
|
||||
})
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
|
||||
```dart
|
||||
final myChannel = supabase.channel('room-3',opts: const RealtimeChannelConfig(
|
||||
ack: true,
|
||||
),
|
||||
```dart
|
||||
final myChannel = supabase.channel('room-3',opts: const RealtimeChannelConfig(
|
||||
ack: true,
|
||||
),
|
||||
|
||||
);
|
||||
);
|
||||
|
||||
myChannel.subscribe( (status, error) async {
|
||||
if (status != RealtimeSubscribeStatus.subscribed) return;
|
||||
myChannel.subscribe( (status, error) async {
|
||||
if (status != RealtimeSubscribeStatus.subscribed) return;
|
||||
|
||||
final serverResponse = await myChannel.sendBroadcastMessage(
|
||||
final serverResponse = await myChannel.sendBroadcastMessage(
|
||||
|
||||
event: 'acknowledge',
|
||||
payload: {},
|
||||
);
|
||||
event: 'acknowledge',
|
||||
payload: {},
|
||||
);
|
||||
|
||||
print('serverResponse: $serverResponse');
|
||||
});
|
||||
```
|
||||
print('serverResponse: $serverResponse');
|
||||
});
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `acknowledgeBroadcasts` parameter to `true`.
|
||||
By default, broadcast messages are only sent to other clients. You can broadcast messages back to the sender by setting Broadcast's `acknowledgeBroadcasts` parameter to `true`.
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("room-2") {
|
||||
broadcast {
|
||||
acknowledgeBroadcasts = true
|
||||
}
|
||||
}
|
||||
```kotlin
|
||||
val myChannel = supabase.channel("room-2") {
|
||||
broadcast {
|
||||
acknowledgeBroadcasts = true
|
||||
}
|
||||
}
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join(blockUntilJoined = true) //You can also use the myChannel.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
myChannel.subscribe(blockUntilSubscribed = true) //You can also use the myChannel.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
|
||||
myChannel.broadcast(event = "acknowledge", buildJsonObject { })
|
||||
```
|
||||
myChannel.broadcast(event = "acknowledge", buildJsonObject { })
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
Use this to guarantee that the server has received the message before resolving `channelD.send`'s promise. If the `ack` config is not set to `true` when creating the channel, the promise returned by `channelD.send` will resolve immediately.
|
||||
@@ -408,42 +403,58 @@ You can also send a Broadcast message by making an HTTP request to Realtime serv
|
||||
defaultActiveId="js"
|
||||
queryGroup="language"
|
||||
>
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
```js
|
||||
const channel = client.channel('test-channel')
|
||||
<TabPanel id="js" label="JavaScript">
|
||||
```js
|
||||
const channel = client.channel('test-channel')
|
||||
|
||||
// No need to subscribe to channel
|
||||
// No need to subscribe to channel
|
||||
|
||||
channel
|
||||
.send({
|
||||
type: 'broadcast',
|
||||
event: 'test',
|
||||
payload: { message: 'Hi' },
|
||||
})
|
||||
.then((resp) => console.log(resp))
|
||||
channel
|
||||
.send({
|
||||
type: 'broadcast',
|
||||
event: 'test',
|
||||
payload: { message: 'Hi' },
|
||||
})
|
||||
.then((resp) => console.log(resp))
|
||||
|
||||
// Remember to clean up the channel
|
||||
// Remember to clean up the channel
|
||||
|
||||
client.removeChannel(channel)
|
||||
client.removeChannel(channel)
|
||||
|
||||
````
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
```dart
|
||||
// No need to subscribe to channel
|
||||
</TabPanel>
|
||||
<TabPanel id="dart" label="Dart">
|
||||
```dart
|
||||
// No need to subscribe to channel
|
||||
|
||||
final channel = supabase.channel('test-channel');
|
||||
final res = await channel.sendBroadcastMessage(
|
||||
event: "test",
|
||||
payload: {
|
||||
'message': 'Hi',
|
||||
},
|
||||
);
|
||||
print(res);
|
||||
````
|
||||
final channel = supabase.channel('test-channel');
|
||||
final res = await channel.sendBroadcastMessage(
|
||||
event: "test",
|
||||
payload: {
|
||||
'message': 'Hi',
|
||||
},
|
||||
);
|
||||
print(res);
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</TabPanel>
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
```kotlin
|
||||
val myChannel = supabase.channel("room-2") {
|
||||
broadcast {
|
||||
acknowledgeBroadcasts = true
|
||||
}
|
||||
}
|
||||
|
||||
// No need to subscribe to channel
|
||||
|
||||
myChannel.broadcast(event = "test", buildJsonObject {
|
||||
put("message", "Hi")
|
||||
})
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
export const Page = ({ children }) => <Layout meta={meta} children={children} />
|
||||
|
||||
@@ -244,7 +244,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("schema-db-changes")
|
||||
val myChannel = supabase.channel("schema-db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction>(schema = "public")
|
||||
|
||||
@@ -258,8 +258,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -313,7 +312,7 @@ final changes = supabase
|
||||
Use `PostgresAction.Insert` as type to listen only to database `INSERT`s:
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Insert>(schema = "public")
|
||||
|
||||
@@ -323,8 +322,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -378,7 +376,7 @@ supabase
|
||||
Use `PostgresAction.Update` as type to listen only to database `UPDATE`s:
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public")
|
||||
|
||||
@@ -388,8 +386,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -443,7 +440,7 @@ supabase
|
||||
Use `PostgresAction.Delete` as type to listen only to database `DELETE`s:
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Delete>(schema = "public")
|
||||
|
||||
@@ -453,8 +450,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -508,7 +504,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction>(schema = "public") {
|
||||
table = "todos"
|
||||
@@ -520,8 +516,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -589,15 +584,14 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
val messageChanges = myChannel.postgresChangeFlow<PostgresAction>(schema = "public") {
|
||||
table = "messages"
|
||||
}
|
||||
val userChanges = myChannel.postgresChangeFlow<PostgresAction.Insert>(schema = "public") {
|
||||
table = "users"
|
||||
}
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -655,7 +649,7 @@ const changes = client
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Insert>(schema = "public") {
|
||||
table = "todos"
|
||||
@@ -668,8 +662,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -731,7 +724,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
|
||||
table = "messages"
|
||||
@@ -744,8 +737,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -879,7 +871,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Insert>(schema = "public") {
|
||||
table = "profiles"
|
||||
@@ -892,8 +884,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -953,7 +944,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
|
||||
table = "profiles"
|
||||
@@ -966,8 +957,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -1027,7 +1017,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
|
||||
table = "products"
|
||||
@@ -1040,8 +1030,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -1101,7 +1090,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
|
||||
table = "products"
|
||||
@@ -1114,8 +1103,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -1175,7 +1163,7 @@ supabase
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
|
||||
table = "products"
|
||||
@@ -1188,8 +1176,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -1303,7 +1290,7 @@ val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
jwtToken = "your-custom-jwt"
|
||||
}
|
||||
}
|
||||
val myChannel = supabase.realtime.createChannel("db-changes")
|
||||
val myChannel = supabase.channel("db-changes")
|
||||
|
||||
val changes = myChannel.postgresChangeFlow<PostgresAction.Update>(schema = "public") {
|
||||
table = "products"
|
||||
@@ -1316,8 +1303,7 @@ changes
|
||||
}
|
||||
.launchIn(yourCoroutineScope)
|
||||
|
||||
supabase.realtime.connect()
|
||||
myChannel.join()
|
||||
myChannel.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
@@ -58,7 +58,7 @@ final supabase = Supabase.instance.client;
|
||||
```kotlin
|
||||
val supabaseUrl = "https://<project>.supabase.co"
|
||||
val supabaseKey = "<your-anon-key>"
|
||||
val client = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
install(Realtime)
|
||||
}
|
||||
```
|
||||
@@ -120,7 +120,7 @@ roomOne.onPresenceSync((_) {
|
||||
Listen to the presence change flow, emitting new a new `PresenceAction` whenever someone joins or leaves:
|
||||
|
||||
```kotlin
|
||||
val roomOne = supabase.realtime.createChannel("room_01")
|
||||
val roomOne = supabase.channel("room_01")
|
||||
val presenceFlow: Flow<PresenceAction> = roomOne.presenceChangeFlow()
|
||||
presenceFlow
|
||||
.onEach {
|
||||
@@ -128,8 +128,8 @@ presenceFlow
|
||||
println(it.leaves) //You can also use it.decodeLeavesAs<YourType>()
|
||||
}
|
||||
.launchIn(yourCoroutineScope) //You can also use .collect { } here
|
||||
supabase.realtime.connect()
|
||||
roomOne.join()
|
||||
|
||||
roomOne.subscribe()
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
@@ -188,15 +188,14 @@ roomOne.subscribe((status, error) async {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val roomOne = supabase.realtime.createChannel("room_01")
|
||||
val roomOne = supabase.channel("room_01")
|
||||
|
||||
val userStatus = UserStatus( //Your custom class
|
||||
user = "user-1",
|
||||
onlineAt = Clock.System.now().toEpochMilliseconds()
|
||||
)
|
||||
|
||||
supabase.realtime.connect()
|
||||
roomOne.join(blockUntilJoined = true) //You can also use the roomOne.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
roomOne.subscribe(blockUntilSubscribed = true) //You can also use the roomOne.status flow instead, but this parameter will block the coroutine until the status is joined.
|
||||
|
||||
roomOne.track(userStatus)
|
||||
```
|
||||
@@ -299,7 +298,7 @@ final channelC = supabase.channel(
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val channelC = supabase.realtime.createChannel("test") {
|
||||
val channelC = supabase.channel("test") {
|
||||
presence {
|
||||
key = "userId-123"
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ supabase.storage.from('bucket').getPublicUrl('image.jpg', {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val url = supabase.storage["bucket"].publicRenderUrl("image.jpg") {
|
||||
val url = supabase.storage.from("bucket").publicRenderUrl("image.jpg") {
|
||||
size(width = 500, height = 600)
|
||||
}
|
||||
```
|
||||
@@ -81,7 +81,7 @@ supabase.storage.from('bucket').createSignedUrl('image.jpg', 60000, {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val url = supabase.storage["bucket"].createSignedUrl("image.jpg", 60.seconds) {
|
||||
val url = supabase.storage.from("bucket").createSignedUrl("image.jpg", 60.seconds) {
|
||||
size(200, 200)
|
||||
}
|
||||
```
|
||||
@@ -117,13 +117,13 @@ supabase.storage.from('bucket').download('image.jpg', {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage["bucket"].downloadAuthenticated("image.jpg") {
|
||||
val data = supabase.storage.from("bucket").downloadAuthenticated("image.jpg") {
|
||||
size(800, 300)
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage["bucket"].downloadAuthenticatedTo("image.jpg", file) {
|
||||
supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
|
||||
size(800, 300)
|
||||
}
|
||||
```
|
||||
@@ -170,14 +170,14 @@ await storage.from('bucket').download('image.jpeg', {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage["bucket"].downloadAuthenticated("image.jpg") {
|
||||
val data = supabase.storage.from("bucket").downloadAuthenticated("image.jpg") {
|
||||
size(200, 200)
|
||||
format = "origin"
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage["bucket"].downloadAuthenticatedTo("image.jpg", file) {
|
||||
supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
|
||||
size(200, 200)
|
||||
format = "origin"
|
||||
}
|
||||
@@ -309,14 +309,14 @@ supabase.storage.from('bucket').download('image.jpg', {
|
||||
<TabPanel id="kotlin" label="Kotlin">
|
||||
|
||||
```kotlin
|
||||
val data = supabase.storage["bucket"].downloadAuthenticated("image.jpg") {
|
||||
val data = supabase.storage.from("bucket").downloadAuthenticated("image.jpg") {
|
||||
size(800, 300)
|
||||
resize = ImageTransformation.Resize.CONTAIN
|
||||
}
|
||||
|
||||
//Or on JVM stream directly to a file
|
||||
val file = File("image.jpg")
|
||||
supabase.storage["bucket"].downloadAuthenticatedTo("image.jpg", file) {
|
||||
supabase.storage.from("bucket").downloadAuthenticatedTo("image.jpg", file) {
|
||||
size(800, 300)
|
||||
resize = ImageTransformation.Resize.CONTAIN
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ Supabase Storage implements the [TUS protocol](https://tus.io/) to enable resuma
|
||||
|
||||
```kotlin
|
||||
suspend fun uploadFile(file: File) {
|
||||
val upload: ResumableUpload = supabase.storage["bucket_name"]
|
||||
val upload: ResumableUpload = supabase.storage.from("bucket_name")
|
||||
.resumable.createOrContinueUpload("file_path", file)
|
||||
upload.stateFlow
|
||||
.onEach {
|
||||
@@ -100,7 +100,7 @@ Supabase Storage implements the [TUS protocol](https://tus.io/) to enable resuma
|
||||
|
||||
// On other platforms you might have to give the bytes directly and specify a source if you want to continue it later:
|
||||
suspend fun uploadData(bytes: ByteArray) {
|
||||
val upload: ResumableUpload = supabase.storage["bucket_name"]
|
||||
val upload: ResumableUpload = supabase.storage.from("bucket_name")
|
||||
.resumable.createOrContinueUpload(bytes, "source", "file_path")
|
||||
|
||||
upload.stateFlow
|
||||
|
||||
@@ -55,12 +55,12 @@ val supabase = createSupabaseClient(supabaseUrl, supabaseKey) {
|
||||
}
|
||||
|
||||
suspend fun uploadData(bytes: ByteArray) {
|
||||
supabase.storage["bucket_name"].upload("file_path", bytes)
|
||||
supabase.storage.from("bucket_name").upload("file_path", bytes)
|
||||
}
|
||||
|
||||
//Or on JVM/Android: (This will stream the data from the file to supabase)
|
||||
suspend fun uploadFile(file: File) {
|
||||
supabase.storage["bucket_name"].upload("file_path", file)
|
||||
supabase.storage.from("bucket_name").upload("file_path", file)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json'
|
||||
import spec from '~/../../spec/supabase_kt_v1.yml' assert { type: 'yml' }
|
||||
import spec from '~/../../spec/supabase_kt_v2.yml' assert { type: 'yml' }
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json'
|
||||
import typeSpec from '~/../../spec/enrichments/tsdoc_v2/combined.json'
|
||||
import spec from '~/../../spec/supabase_kt_v1.yml' assert { type: 'yml' }
|
||||
import spec from '~/../../spec/supabase_kt_v2.yml' assert { type: 'yml' }
|
||||
import RefSectionHandler from '~/components/reference/RefSectionHandler'
|
||||
import { flattenSections } from '~/lib/helpers'
|
||||
import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
@@ -14,7 +14,7 @@ const libraryPath = '/kotlin'
|
||||
export default function KotlinReference(props) {
|
||||
const router = useRouter()
|
||||
const slug = router.query.slug[0]
|
||||
const filteredSection = sections.filter((section) => section.id === slug)
|
||||
const filteredSection = sections.filter((section) => section.slug === slug)
|
||||
|
||||
const pageTitle = filteredSection[0]?.title
|
||||
? `${filteredSection[0]?.title} | Supabase`
|
||||
|
||||
+10
-2
@@ -6,10 +6,18 @@ import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths'
|
||||
import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/kotlin/v0'
|
||||
const libraryPath = '/kotlin/v1'
|
||||
|
||||
export default function KotlinReference(props) {
|
||||
return <RefSectionHandler sections={sections} spec={spec} pageProps={props} type="client-lib" />
|
||||
return (
|
||||
<RefSectionHandler
|
||||
sections={sections}
|
||||
spec={spec}
|
||||
pageProps={props}
|
||||
type="client-lib"
|
||||
isOldVersion
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
+1
-1
@@ -9,7 +9,7 @@ import { useRouter } from 'next/router'
|
||||
import RefSEO from '~/components/reference/RefSEO'
|
||||
|
||||
const sections = flattenSections(clientLibsCommonSections)
|
||||
const libraryPath = '/kotlin/v0'
|
||||
const libraryPath = '/kotlin/v1'
|
||||
|
||||
export default function KotlinReference(props) {
|
||||
const router = useRouter()
|
||||
@@ -33,7 +33,8 @@
|
||||
"reference_python_v2",
|
||||
"reference_csharp_v0",
|
||||
"reference_swift_v1",
|
||||
"reference_kotlin_v0"
|
||||
"reference_kotlin_v1",
|
||||
"reference_kotlin_v2"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -47,7 +48,8 @@
|
||||
"reference_python_v2",
|
||||
"reference_csharp_v0",
|
||||
"reference_swift_v1",
|
||||
"reference_kotlin_v0"
|
||||
"reference_kotlin_v1",
|
||||
"reference_kotlin_v2"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -963,7 +965,8 @@
|
||||
"reference_python_v2",
|
||||
"reference_csharp_v0",
|
||||
"reference_swift_v1",
|
||||
"reference_kotlin_v0"
|
||||
"reference_kotlin_v1",
|
||||
"reference_kotlin_v2"
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
|
||||
@@ -2098,15 +2098,15 @@ functions:
|
||||
Creates a new user.
|
||||
- By default, the user needs to verify their email address before logging in. To turn this off, disable **Confirm email** in [your project](https://supabase.com/dashboard/project/_/auth/providers).
|
||||
- **Confirm email** determines if users need to confirm their email address after signing up.
|
||||
- If **Confirm email** is enabled, the return value is null and you will be logged in instead.
|
||||
- If **Confirm email** is disabled, the return value is the user and you won't be logged in automatically.
|
||||
- If **Confirm email** is enabled, the return value is the user and you won't be logged in automatically.
|
||||
- If **Confirm email** is disabled, the return value is null and you will be logged in instead.
|
||||
- When the user confirms their email address, they are redirected to the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url) by default. You can modify your `SITE_URL` or add additional redirect URLs in [your project](https://supabase.com/dashboard/project/_/auth/url-configuration).
|
||||
- To learn how to handle OTP links & OAuth refer to [initializing](/docs/reference/kotlin/initializing)
|
||||
- If signUpWith() is called for an existing confirmed user:
|
||||
- If **Confirm email** is enabled in [your project](https://supabase.com/dashboard/project/_/auth/providers), an obfuscated/fake user object is returned.
|
||||
- If **Confirm email** is disabled, the error message, `User already registered` is returned.
|
||||
examples:
|
||||
- id: sign-up-phone
|
||||
- id: sign-up-email
|
||||
name: Sign up with email
|
||||
isSpotlight: true
|
||||
code: |
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user