├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── feature_request.yml
│ └── question.yml
├── dependabot.yml
├── images
│ ├── desktop_supabase.png
│ └── img.png
├── labeler.yml
└── workflows
│ ├── build.yml
│ ├── cache.yml
│ ├── detekt.yml
│ ├── dokka.yml
│ ├── labeler.yml
│ ├── release.yml
│ ├── samples.yml
│ └── test.yml
├── .gitignore
├── Auth
├── README.md
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── Android.kt
│ │ ├── AuthConfig.kt
│ │ ├── RedirectUrl.android.kt
│ │ ├── Utils.android.kt
│ │ ├── providers
│ │ └── ExternalAuthConfig.kt
│ │ └── setupPlatform.kt
│ ├── androidUnitTest
│ └── kotlin
│ │ └── platformSettings.kt
│ ├── appleMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── Apple.kt
│ │ ├── RedirectUrl.apple.kt
│ │ ├── Utils.apple.kt
│ │ ├── providers
│ │ ├── ExternalAuthConfig.kt
│ │ └── OAuthProvider.kt
│ │ └── setupPlatform.kt
│ ├── appleTest
│ └── kotlin
│ │ └── platformSettings.kt
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── AccessToken.kt
│ │ ├── Auth.kt
│ │ ├── AuthConfig.kt
│ │ ├── AuthExtensions.kt
│ │ ├── AuthImpl.kt
│ │ ├── AuthenticatedSupabaseApi.kt
│ │ ├── CodeVerifierCache.kt
│ │ ├── GoTrueErrorResponse.kt
│ │ ├── JsonUtils.kt
│ │ ├── MinimalConfig.kt
│ │ ├── OtpType.kt
│ │ ├── PKCE.kt
│ │ ├── PostgrestFilterDSL.kt
│ │ ├── RedirectUrl.kt
│ │ ├── SessionManager.kt
│ │ ├── SignOutScope.kt
│ │ ├── UrlLauncher.kt
│ │ ├── UrlUtils.kt
│ │ ├── Utils.kt
│ │ ├── admin
│ │ ├── AdminApi.kt
│ │ ├── AdminUserBuilder.kt
│ │ ├── AdminUserUpdateBuilder.kt
│ │ └── LinkType.kt
│ │ ├── event
│ │ └── AuthEvent.kt
│ │ ├── exception
│ │ ├── AuthErrorCode.kt
│ │ ├── AuthRestException.kt
│ │ ├── AuthSessionMissingException.kt
│ │ └── AuthWeakPasswordException.kt
│ │ ├── mfa
│ │ ├── AuthenticatorAssuranceLevel.kt
│ │ ├── FactorType.kt
│ │ ├── MfaApi.kt
│ │ ├── MfaChallenge.kt
│ │ ├── MfaFactor.kt
│ │ └── MfaStatus.kt
│ │ ├── providers
│ │ ├── AuthProvider.kt
│ │ ├── ExternalAuthConfig.kt
│ │ ├── IDTokenProvider.kt
│ │ ├── OAuthProvider.kt
│ │ ├── Providers.kt
│ │ └── builtin
│ │ │ ├── CaptchaTokenSerializer.kt
│ │ │ ├── DefaultAuthProvider.kt
│ │ │ ├── Email.kt
│ │ │ ├── IDToken.kt
│ │ │ ├── OTP.kt
│ │ │ ├── Phone.kt
│ │ │ └── SSO.kt
│ │ ├── status
│ │ ├── RefreshFailureCause.kt
│ │ ├── SessionSource.kt
│ │ └── SessionStatus.kt
│ │ └── user
│ │ ├── Identity.kt
│ │ ├── UserInfo.kt
│ │ ├── UserSession.kt
│ │ └── UserUpdateBuilder.kt
│ ├── commonTest
│ └── kotlin
│ │ ├── AccessTokenTest.kt
│ │ ├── AdminApiTest.kt
│ │ ├── AuthApiTest.kt
│ │ ├── AuthRestExceptionTest.kt
│ │ ├── AuthTest.kt
│ │ ├── AuthTestUtils.kt
│ │ ├── CodeVerifierCacheTest.kt
│ │ ├── MemorySessionManagerTest.kt
│ │ ├── MfaApiTest.kt
│ │ └── UrlUtilsTest.kt
│ ├── desktopMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── AuthConfig.kt
│ │ ├── Utils.desktop.kt
│ │ └── server
│ │ ├── HttpCallbackHtml.kt
│ │ ├── HttpCallbackRoutes.kt
│ │ └── HttpCallbackServer.kt
│ ├── iosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── AuthConfig.kt
│ │ └── providers
│ │ └── openUrl.kt
│ ├── jsMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── AuthConfig.kt
│ │ ├── RedirectUrl.js.kt
│ │ ├── Utils.js.kt
│ │ ├── providers
│ │ └── ExternalAuthConfig.kt
│ │ └── setupPlatform.kt
│ ├── jsTest
│ └── kotlin
│ │ └── platformSettings.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── RedirectUrl.jvm.kt
│ │ ├── Utils.jvm.kt
│ │ ├── providers
│ │ └── ExternalAuthConfig.kt
│ │ └── setupPlatform.kt
│ ├── jvmTest
│ └── kotlin
│ │ └── platformSettings.kt
│ ├── linuxMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── SettingsUtil.kt
│ │ ├── Utils.linux.kt
│ │ ├── generateRedirectUrl.kt
│ │ ├── providers
│ │ └── ExternalAuthConfig.kt
│ │ └── setupPlatform.kt
│ ├── linuxTest
│ └── kotlin
│ │ └── platformSettings.kt
│ ├── macosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ └── providers
│ │ └── openUrl.kt
│ ├── mingwMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── Utils.mingw.kt
│ │ ├── generateRedirectUrl.kt
│ │ ├── providers
│ │ └── ExternalAuthConfig.kt
│ │ └── setupPlatform.kt
│ ├── mingwTest
│ └── kotlin
│ │ └── platformSettings.kt
│ ├── nonDesktopMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ └── Utils.kt
│ ├── settingsMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── SettingsCodeVerifierCache.kt
│ │ ├── SettingsSessionManager.kt
│ │ └── SettingsUtil.kt
│ ├── settingsTest
│ └── kotlin
│ │ ├── SettingsCodeVerifierCacheTest.kt
│ │ ├── SettingsSessionManagerTest.kt
│ │ └── SettingsTest.kt
│ ├── tvosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── AuthConfig.kt
│ │ └── providers
│ │ └── openUrl.kt
│ ├── wasmJsMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── auth
│ │ ├── AuthConfig.kt
│ │ ├── RedirectUrl.kt
│ │ ├── Utils.wasmJs.kt
│ │ ├── providers
│ │ └── ExternalAuthConfig.kt
│ │ └── setupPlatform.kt
│ ├── wasmJsTest
│ └── kotlin
│ │ └── platformSettings.kt
│ └── watchosMain
│ └── kotlin
│ └── io
│ └── github
│ └── jan
│ └── supabase
│ └── auth
│ ├── AuthConfig.kt
│ └── providers
│ └── openUrl.kt
├── CHANGELOG.md
├── CODEOWNERS
├── CONTRIBUTING.md
├── Functions
├── README.md
├── build.gradle.kts
└── src
│ ├── androidMain
│ └── AndroidManifest.xml
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── functions
│ │ ├── EdgeFunction.kt
│ │ ├── FunctionRegion.kt
│ │ └── Functions.kt
│ └── commonTest
│ └── kotlin
│ ├── EdgeFunctionTest.kt
│ └── FunctionsTest.kt
├── GoTrue
└── README.md
├── LICENSE
├── MIGRATION.md
├── Postgrest
├── README.md
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ └── getColumnName.kt
│ ├── appleMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ └── getColumnName.kt
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ ├── Postgrest.kt
│ │ ├── PostgrestDsl.kt
│ │ ├── PostgrestErrorResponse.kt
│ │ ├── PostgrestImpl.kt
│ │ ├── PostgrestRpc.kt
│ │ ├── PropertyConversionMethod.kt
│ │ ├── Utils.kt
│ │ ├── exception
│ │ └── PostgrestRestException.kt
│ │ ├── executor
│ │ ├── PostgrestHttpExtension.kt
│ │ ├── RequestExecutor.kt
│ │ └── RestRequestExecutor.kt
│ │ ├── query
│ │ ├── Columns.kt
│ │ ├── Order.kt
│ │ ├── PostgrestQueryBuilder.kt
│ │ ├── PostgrestRequestBuilder.kt
│ │ ├── PostgrestUpdate.kt
│ │ ├── filter
│ │ │ ├── FilterOperation.kt
│ │ │ ├── FilterOperator.kt
│ │ │ ├── PostgrestFilterBuilder.kt
│ │ │ └── TextSearchType.kt
│ │ └── request
│ │ │ ├── InsertRequestBuilder.kt
│ │ │ ├── RpcRequestBuilder.kt
│ │ │ ├── SelectRequestBuilder.kt
│ │ │ └── UpsertRequestBuilder.kt
│ │ ├── request
│ │ ├── DeleteRequest.kt
│ │ ├── InsertRequest.kt
│ │ ├── PostgrestRequest.kt
│ │ ├── RpcRequest.kt
│ │ ├── SelectRequest.kt
│ │ └── UpdateRequest.kt
│ │ └── result
│ │ └── PostgrestResult.kt
│ ├── commonTest
│ └── kotlin
│ │ ├── ColumnsTest.kt
│ │ ├── PostgrestFilterBuilderTest.kt
│ │ ├── PostgrestRequestBuilderTest.kt
│ │ ├── PostgrestTest.kt
│ │ ├── Utils.kt
│ │ └── request
│ │ ├── DeleteRequestTest.kt
│ │ ├── InsertRequestTest.kt
│ │ ├── RpcRequestTest.kt
│ │ ├── SelectRequestTest.kt
│ │ └── UpdateRequestTest.kt
│ ├── jsMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ └── getColumnName.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ └── getColumnName.kt
│ ├── linuxX64Main
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ └── getSerialName.kt
│ ├── mingwX64Main
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── postgrest
│ │ └── getSerialName.kt
│ └── wasmJsMain
│ └── kotlin
│ └── io
│ └── github
│ └── jan
│ └── supabase
│ └── postgrest
│ └── getColumnName.kt
├── README.md
├── Realtime
├── README.md
├── build.gradle.kts
└── src
│ ├── androidMain
│ └── AndroidManifest.xml
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── realtime
│ │ ├── CallbackManager.kt
│ │ ├── PostgresAction.kt
│ │ ├── PostgresChangeFilter.kt
│ │ ├── PostgrestExtensions.kt
│ │ ├── PresenceAction.kt
│ │ ├── Realtime.kt
│ │ ├── RealtimeCallback.kt
│ │ ├── RealtimeChannel.kt
│ │ ├── RealtimeChannelBuilder.kt
│ │ ├── RealtimeChannelImpl.kt
│ │ ├── RealtimeExt.kt
│ │ ├── RealtimeImpl.kt
│ │ ├── RealtimeJoinPayload.kt
│ │ ├── RealtimeMessage.kt
│ │ ├── RealtimeTopic.kt
│ │ ├── annotations
│ │ └── ChannelDsl.kt
│ │ ├── data
│ │ ├── BroadcastApiBody.kt
│ │ └── PostgresActionData.kt
│ │ ├── event
│ │ ├── RBroadcastEvent.kt
│ │ ├── RCloseEvent.kt
│ │ ├── RErrorEvent.kt
│ │ ├── RPostgresChangesEvent.kt
│ │ ├── RPostgresServerChangesEvent.kt
│ │ ├── RPresenceDiffEvent.kt
│ │ ├── RPresenceStateEvent.kt
│ │ ├── RSystemEvent.kt
│ │ ├── RSystemReplyEvent.kt
│ │ ├── RTokenExpiredEvent.kt
│ │ └── RealtimeEvent.kt
│ │ └── websocket
│ │ ├── KtorRealtimeWebsocket.kt
│ │ ├── KtorRealtimeWebsocketFactory.kt
│ │ ├── RealtimeWebsocket.kt
│ │ └── RealtimeWebsocketFactory.kt
│ └── commonTest
│ └── kotlin
│ ├── CallbackManagerTest.kt
│ ├── RealtimeChannelTest.kt
│ ├── RealtimeEventTest.kt
│ ├── RealtimeExtTest.kt
│ ├── RealtimeTest.kt
│ ├── RealtimeTestUtils.kt
│ ├── RealtimeTopicTest.kt
│ └── RealtimeWSMock.kt
├── Storage
├── README.md
├── build.gradle.kts
└── src
│ ├── androidAndJvmMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── storage
│ │ ├── JvmUtils.kt
│ │ └── ResumableUtils.kt
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── storage
│ │ ├── AndroidUtils.kt
│ │ ├── Context.kt
│ │ └── ResumableAndroidUtils.kt
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── storage
│ │ ├── Bucket.kt
│ │ ├── BucketApi.kt
│ │ ├── BucketApiImpl.kt
│ │ ├── BucketBuilder.kt
│ │ ├── BucketListFilter.kt
│ │ ├── DownloadOptionBuilder.kt
│ │ ├── FileObject.kt
│ │ ├── FileSizeLimit.kt
│ │ ├── FileUploadResponse.kt
│ │ ├── FlowExtension.kt
│ │ ├── ImageTransformation.kt
│ │ ├── NetworkStatus.kt
│ │ ├── SignedUrl.kt
│ │ ├── Storage.kt
│ │ ├── StorageErrorResponse.kt
│ │ ├── StorageItem.kt
│ │ ├── UploadData.kt
│ │ ├── UploadOptionBuilder.kt
│ │ ├── UploadSignedUrl.kt
│ │ ├── Utils.kt
│ │ └── resumable
│ │ ├── Fingerprint.kt
│ │ ├── MemoryResumableCache.kt
│ │ ├── ResumableCache.kt
│ │ ├── ResumableClient.kt
│ │ ├── ResumableUpload.kt
│ │ ├── ResumableUploadState.kt
│ │ └── StreamContent.kt
│ ├── commonTest
│ └── kotlin
│ │ ├── BucketApiFlowTest.kt
│ │ ├── BucketApiTest.kt
│ │ ├── BucketListFilterTest.kt
│ │ └── StorageTest.kt
│ ├── linuxMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── storage
│ │ └── resumable
│ │ └── ResumableCacheUtil.kt
│ └── settingsMain
│ └── kotlin
│ └── io
│ └── github
│ └── jan
│ └── supabase
│ └── storage
│ └── resumable
│ └── SettingsResumableCache.kt
├── Supabase
├── README.md
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.android.kt
│ │ └── PlatformTarget.kt
│ ├── androidUnitTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── appleMain
│ └── kotlin
│ │ └── io
│ │ └── supabase
│ │ └── supabase
│ │ └── Utils.kt
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── AccessTokenProvider.kt
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.kt
│ │ ├── SupabaseClient.kt
│ │ ├── SupabaseClientBuilder.kt
│ │ ├── SupabaseClientConfig.kt
│ │ ├── SupabaseSerializer.kt
│ │ ├── Utils.kt
│ │ ├── annotations
│ │ ├── SupabaseDsl.kt
│ │ ├── SupabaseExperimental.kt
│ │ └── SupabaseInternal.kt
│ │ ├── collections
│ │ ├── AtomicMutableList.kt
│ │ └── AtomicMutableMap.kt
│ │ ├── exceptions
│ │ ├── HttpRequestException.kt
│ │ ├── RestException.kt
│ │ └── SupabaseEncodingException.kt
│ │ ├── logging
│ │ ├── LogLevel.kt
│ │ └── SupabaseLogger.kt
│ │ ├── network
│ │ ├── KtorSupabaseHttpClient.kt
│ │ ├── SupabaseApi.kt
│ │ └── SupabaseHttpClient.kt
│ │ ├── plugins
│ │ ├── CustomSerializationConfig.kt
│ │ ├── CustomSerializationPlugin.kt
│ │ ├── MainPlugin.kt
│ │ ├── PluginManager.kt
│ │ ├── SerializableData.kt
│ │ ├── SupabasePlugin.kt
│ │ └── SupabasePluginProvider.kt
│ │ └── serializer
│ │ └── KotlinXSerializer.kt
│ ├── commonTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── iosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.ios.kt
│ │ └── PlatformTarget.kt
│ ├── iosTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── jsMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.js.kt
│ │ └── PlatformTarget.kt
│ ├── jsTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.jvm.kt
│ │ └── PlatformTarget.kt
│ ├── jvmTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── linuxMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.kt
│ │ └── PlatformTarget.linux.kt
│ ├── linuxTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── macosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.kt
│ │ └── PlatformTarget.macos.kt
│ ├── macosTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── mingwMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── PlatformTarget.mingw.kt
│ ├── mingwX64Main
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── CurrentPlatformTarget.kt
│ │ └── DefaultDispatcher.kt
│ ├── mingwX64Test
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── tvosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.kt
│ │ └── PlatformTarget.tvos.kt
│ ├── tvosTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── wasmJsMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ └── PlatformTarget.wasmJs.kt
│ ├── wasmJsTest
│ └── kotlin
│ │ └── PlatformTargetTest.kt
│ ├── watchosMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ ├── DefaultDispatcher.kt
│ │ ├── PlatformTarget.kt
│ │ └── PlatformTarget.watchos.kt
│ └── watchosTest
│ └── kotlin
│ └── PlatformTargetTest.kt
├── TROUBLESHOOTING.md
├── bom
└── build.gradle.kts
├── build.gradle.kts
├── buildSrc
├── build.gradle.kts
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── Android.kt
│ ├── Detekt.kt
│ ├── Dokka.kt
│ ├── KotlinPlugin.kt
│ ├── KotlinTargets.kt
│ ├── Modules.kt
│ ├── PowerAssert.kt
│ ├── Publishing.kt
│ └── TargetHierarchy.kt
├── demos
├── android-login
│ ├── .gitignore
│ ├── README.md
│ ├── android
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── android
│ │ │ ├── MainActivity.kt
│ │ │ └── MainApplication.kt
│ ├── build.gradle.kts
│ ├── buildSrc
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ └── kotlin
│ │ │ └── Versions.kt
│ ├── common
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── androidMain
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── MPViewModel.kt
│ │ │ │ └── di
│ │ │ │ ├── platformGoTrueConfig.kt
│ │ │ │ └── viewModel.kt
│ │ │ └── commonMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── AppViewModel.kt
│ │ │ ├── di
│ │ │ ├── koin.kt
│ │ │ ├── supabaseModule.kt
│ │ │ └── viewModelModule.kt
│ │ │ └── ui
│ │ │ ├── components
│ │ │ ├── OAuthWebView.kt
│ │ │ └── PasswordField.kt
│ │ │ └── screen
│ │ │ ├── LoginScreen.kt
│ │ │ └── OAuthScreen.kt
│ ├── gradle.properties
│ ├── gradle
│ │ ├── libs.versions.toml
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── kotlin-js-store
│ │ └── yarn.lock
│ └── settings.gradle.kts
└── multiplatform-deeplinks
│ ├── .gitignore
│ ├── README.md
│ ├── android
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── android
│ │ ├── MainActivity.kt
│ │ └── MainApplication.kt
│ ├── build.gradle.kts
│ ├── buildSrc
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── Versions.kt
│ ├── common
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── MPViewModel.kt
│ │ │ ├── di
│ │ │ ├── platformGoTrueConfig.kt
│ │ │ └── viewModel.kt
│ │ │ └── ui
│ │ │ └── components
│ │ │ └── AlertDialog.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── App.kt
│ │ │ ├── AppViewModel.kt
│ │ │ ├── di
│ │ │ ├── koin.kt
│ │ │ ├── netModule.kt
│ │ │ ├── supabaseModule.kt
│ │ │ └── viewModelModule.kt
│ │ │ └── ui
│ │ │ ├── components
│ │ │ ├── AlertDialog.kt
│ │ │ ├── GoogleButton.kt
│ │ │ └── PasswordField.kt
│ │ │ ├── icons
│ │ │ └── Google.kt
│ │ │ └── screen
│ │ │ ├── AppScreen.kt
│ │ │ └── LoginScreen.kt
│ │ └── desktopMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── common
│ │ ├── MPViewModel.kt
│ │ ├── di
│ │ ├── platformGoTrueConfig.kt
│ │ └── viewModel.kt
│ │ └── ui
│ │ └── components
│ │ └── AlertDialog.kt
│ ├── desktop
│ ├── build.gradle.kts
│ ├── conveyor.conf
│ ├── icons
│ │ └── icon.svg
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ └── Main.kt
│ ├── gradle.properties
│ ├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── kotlin-js-store
│ └── yarn.lock
│ └── settings.gradle.kts
├── detekt.yml
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── plugins
├── ApolloGraphQL
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── AndroidManifest.xml
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── graphql
│ │ │ ├── ApolloHttpInterceptor.kt
│ │ │ └── GraphQL.kt
│ │ └── commonTest
│ │ └── kotlin
│ │ ├── ApolloHttpInterceptorTest.kt
│ │ └── GraphQLTest.kt
├── Coil3Integration
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── AndroidManifest.xml
│ │ └── commonMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── coil
│ │ ├── Coil3Integration.kt
│ │ └── SupabaseStorageFetcher.kt
├── CoilIntegration
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ └── AndroidManifest.xml
│ │ └── commonMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── coil
│ │ ├── CoilIntegration.kt
│ │ └── SupabaseStorageFetcher.kt
├── ComposeAuth
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── compose
│ │ │ └── auth
│ │ │ ├── SupabaseInitializer.kt
│ │ │ ├── Utils.kt
│ │ │ └── composable
│ │ │ ├── AppleAuth.kt
│ │ │ └── GoogleAuth.kt
│ │ ├── appleMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── compose
│ │ │ └── auth
│ │ │ └── composable
│ │ │ ├── AppleAuth.kt
│ │ │ └── GoogleAuth.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── compose
│ │ │ └── auth
│ │ │ ├── AppleLoginConfig.kt
│ │ │ ├── ComposeAuth.kt
│ │ │ ├── DefaultBehavior.kt
│ │ │ ├── GoogleLoginConfig.kt
│ │ │ ├── Utils.common.kt
│ │ │ └── composable
│ │ │ ├── NativeAppleAuth.kt
│ │ │ ├── NativeGoogleAuth.kt
│ │ │ ├── NativeSignInResult.kt
│ │ │ └── NativeSignInState.kt
│ │ └── noDefaultMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── compose
│ │ └── auth
│ │ └── composable
│ │ ├── AppleAuth.kt
│ │ └── GoogleAuth.kt
├── ComposeAuthUI
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── compose
│ │ │ └── auth
│ │ │ └── ui
│ │ │ └── AndroidSvgPainter.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── compose
│ │ │ └── auth
│ │ │ └── ui
│ │ │ ├── AuthIcons.kt
│ │ │ ├── AuthState.kt
│ │ │ ├── FormComponent.kt
│ │ │ ├── FormValidator.kt
│ │ │ ├── ProviderButton.kt
│ │ │ ├── ProviderIcons.kt
│ │ │ ├── SvgPainter.kt
│ │ │ ├── annotations
│ │ │ └── AuthUiExperimental.kt
│ │ │ ├── email
│ │ │ └── EmailField.kt
│ │ │ ├── password
│ │ │ ├── PasswordField.kt
│ │ │ └── PasswordRule.kt
│ │ │ └── phone
│ │ │ ├── PhoneField.kt
│ │ │ └── PhoneVisualTransformation.kt
│ │ ├── jvmMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── compose
│ │ │ └── auth
│ │ │ └── ui
│ │ │ └── SvgPainterJvm.kt
│ │ └── nonJvmMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── compose
│ │ └── auth
│ │ └── ui
│ │ ├── DrawCache.kt
│ │ └── SvgPainterNonJvm.kt
└── ImageLoaderIntegration
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ ├── androidMain
│ └── AndroidManifest.xml
│ └── commonMain
│ └── kotlin
│ └── io
│ └── github
│ └── jan
│ └── supabase
│ └── imageloader
│ ├── ImageLoaderIntegration.kt
│ └── SupabaseStorageFetcher.kt
├── sample
├── chat-demo-mpp
│ ├── README.md
│ ├── android
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── android
│ │ │ ├── MainActivity.kt
│ │ │ └── MainApplication.kt
│ ├── chatdemoios
│ │ └── chatdemoios.xcodeproj
│ │ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── common
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── androidMain
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── MPViewModel.kt
│ │ │ │ └── di
│ │ │ │ ├── platformGoTrueConfig.kt
│ │ │ │ └── viewModel.kt
│ │ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── App.kt
│ │ │ │ ├── ChatViewModel.kt
│ │ │ │ ├── di
│ │ │ │ ├── koin.kt
│ │ │ │ ├── netModule.kt
│ │ │ │ ├── supabaseModule.kt
│ │ │ │ └── viewModelModule.kt
│ │ │ │ ├── net
│ │ │ │ ├── AuthApi.kt
│ │ │ │ └── MessageApi.kt
│ │ │ │ └── ui
│ │ │ │ ├── components
│ │ │ │ ├── MessageCard.kt
│ │ │ │ ├── OTPDialog.kt
│ │ │ │ ├── PasswordChangeDialog.kt
│ │ │ │ ├── PasswordField.kt
│ │ │ │ └── PasswordRecoverDialog.kt
│ │ │ │ ├── icons
│ │ │ │ └── Google.kt
│ │ │ │ └── screen
│ │ │ │ ├── ChatScreen.kt
│ │ │ │ └── LoginScreen.kt
│ │ │ ├── desktopMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── MPViewModel.kt
│ │ │ │ └── di
│ │ │ │ ├── platformGoTrueConfig.kt
│ │ │ │ └── viewModel.kt
│ │ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── App.kt
│ │ │ │ ├── MPViewModel.kt
│ │ │ │ └── di
│ │ │ │ ├── platformGoTrueConfig.kt
│ │ │ │ └── viewModel.kt
│ │ │ └── jsMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── MPViewModel.kt
│ │ │ └── di
│ │ │ ├── platformGoTrueConfig.kt
│ │ │ └── viewModel.kt
│ ├── desktop
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── jvmMain
│ │ │ └── kotlin
│ │ │ └── Main.kt
│ ├── ios
│ │ ├── chatdemoios.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ ├── project.xcworkspace
│ │ │ │ ├── contents.xcworkspacedata
│ │ │ │ ├── xcshareddata
│ │ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ │ └── WorkspaceSettings.xcsettings
│ │ │ │ └── xcuserdata
│ │ │ │ │ └── hieuvu.xcuserdatad
│ │ │ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ │ │ └── WorkspaceSettings.xcsettings
│ │ │ ├── xcshareddata
│ │ │ │ └── xcschemes
│ │ │ │ │ └── chatdemoios.xcscheme
│ │ │ └── xcuserdata
│ │ │ │ └── hieuvu.xcuserdatad
│ │ │ │ └── xcschemes
│ │ │ │ └── xcschememanagement.plist
│ │ ├── chatdemoios.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ ├── xcshareddata
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ │ └── xcuserdata
│ │ │ │ └── hieuvu.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ └── chatdemoios
│ │ │ ├── Assets.xcassets
│ │ │ ├── AccentColor.colorset
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ │ ├── ContentView.swift
│ │ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ │ ├── chatdemoios.entitlements
│ │ │ └── chatdemoiosApp.swift
│ └── web
│ │ ├── build.gradle.kts
│ │ └── src
│ │ └── jsMain
│ │ ├── kotlin
│ │ └── Main.kt
│ │ └── resources
│ │ ├── index.html
│ │ └── styles.css
├── file-upload
│ ├── README.md
│ ├── android
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── android
│ │ │ ├── MainActivity.kt
│ │ │ └── MainApplication.kt
│ ├── common
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── androidMain
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── MPViewModel.kt
│ │ │ │ ├── SupabaseInitializer.kt
│ │ │ │ ├── Uploads.android.kt
│ │ │ │ ├── di
│ │ │ │ └── viewModel.kt
│ │ │ │ ├── parseFileTreeFromPath.kt
│ │ │ │ └── ui
│ │ │ │ ├── components
│ │ │ │ └── AlertDialog.kt
│ │ │ │ └── utils
│ │ │ │ ├── applyDragging.kt
│ │ │ │ └── bytesToBitmap.kt
│ │ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── jan
│ │ │ │ └── supabase
│ │ │ │ └── common
│ │ │ │ ├── App.kt
│ │ │ │ ├── UploadViewModel.kt
│ │ │ │ ├── Uploads.kt
│ │ │ │ ├── Utils.kt
│ │ │ │ ├── di
│ │ │ │ ├── koin.kt
│ │ │ │ ├── supabaseModule.kt
│ │ │ │ └── viewModelModule.kt
│ │ │ │ └── ui
│ │ │ │ ├── components
│ │ │ │ ├── AlertDialog.kt
│ │ │ │ └── UploadCard.kt
│ │ │ │ ├── screen
│ │ │ │ └── UploadScreen.kt
│ │ │ │ └── utils
│ │ │ │ ├── Bitmap.kt
│ │ │ │ ├── Dragging.kt
│ │ │ │ └── FileSize.kt
│ │ │ └── desktopMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── MPViewModel.kt
│ │ │ ├── Uploads.desktop.kt
│ │ │ ├── di
│ │ │ └── viewModel.kt
│ │ │ ├── parseFileTreeFromPath.kt
│ │ │ └── ui
│ │ │ ├── components
│ │ │ └── AlertDialog.kt
│ │ │ └── utils
│ │ │ ├── applyDragging.kt
│ │ │ └── bytesToBitmap.kt
│ └── desktop
│ │ ├── build.gradle.kts
│ │ └── src
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── Main.kt
└── multi-factor-auth
│ ├── README.md
│ ├── android
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── android
│ │ ├── MainActivity.kt
│ │ └── MainApplication.kt
│ ├── common
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── MPViewModel.kt
│ │ │ ├── di
│ │ │ ├── platformGoTrueConfig.kt
│ │ │ └── viewModel.kt
│ │ │ └── ui
│ │ │ └── components
│ │ │ ├── AlertDialog.kt
│ │ │ └── QRCode.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── App.kt
│ │ │ ├── AppViewModel.kt
│ │ │ ├── di
│ │ │ ├── koin.kt
│ │ │ ├── netModule.kt
│ │ │ ├── supabaseModule.kt
│ │ │ └── viewModelModule.kt
│ │ │ └── ui
│ │ │ ├── components
│ │ │ ├── AlertDialog.kt
│ │ │ ├── GoogleButton.kt
│ │ │ ├── PasswordField.kt
│ │ │ └── QRCode.kt
│ │ │ ├── icons
│ │ │ └── Google.kt
│ │ │ └── screen
│ │ │ ├── AppScreen.kt
│ │ │ ├── LoginScreen.kt
│ │ │ ├── MfaLoginScreen.kt
│ │ │ ├── MfaScreen.kt
│ │ │ └── MfaSetupScreen.kt
│ │ ├── desktopMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── common
│ │ │ ├── MPViewModel.kt
│ │ │ ├── di
│ │ │ ├── platformGoTrueConfig.kt
│ │ │ └── viewModel.kt
│ │ │ └── ui
│ │ │ └── components
│ │ │ ├── AlertDialog.kt
│ │ │ └── QRCode.kt
│ │ └── jsMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── common
│ │ ├── MPViewModel.kt
│ │ ├── di
│ │ ├── platformGoTrueConfig.kt
│ │ └── viewModel.kt
│ │ └── ui
│ │ └── components
│ │ ├── AlertDialog.kt
│ │ └── QRCode.kt
│ ├── desktop
│ ├── build.gradle.kts
│ └── src
│ │ └── jvmMain
│ │ └── kotlin
│ │ └── Main.kt
│ └── web
│ ├── build.gradle.kts
│ └── src
│ └── jsMain
│ ├── kotlin
│ └── Main.kt
│ └── resources
│ ├── index.html
│ └── styles.css
├── serializers
├── Jackson
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── jan
│ │ │ └── supabase
│ │ │ └── serializer
│ │ │ └── JacksonSerializer.kt
│ │ └── commonTest
│ │ └── kotlin
│ │ └── JacksonSerializerTest.kt
└── Moshi
│ ├── README.md
│ ├── build.gradle.kts
│ └── src
│ ├── commonMain
│ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── jan
│ │ └── supabase
│ │ └── serializer
│ │ └── MoshiSerializer.kt
│ └── commonTest
│ └── kotlin
│ └── MoshiSerializerTest.kt
├── settings.gradle.kts
└── test-common
├── build.gradle.kts
└── src
├── androidMain
└── AndroidManifest.xml
├── commonMain
└── kotlin
│ └── io
│ └── github
│ └── jan
│ └── supabase
│ └── testing
│ ├── KtorUtils.kt
│ ├── RouteUtils.kt
│ ├── SupabaseClientMock.kt
│ └── TestUtils.kt
└── commonTest
└── kotlin
├── DummySerializer.kt
├── SupabaseClientTest.kt
└── TestPlugin.kt
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: jantennert
2 | github: jan-tennert
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Template for feature request
3 | title: '[Feature request]: '
4 | labels: ["enhancement"]
5 | body:
6 | - type: checkboxes
7 | id: latest-version
8 | attributes:
9 | label: General Info
10 | options:
11 | - label: I installed the latest version of Supabase Kt
12 | required: true
13 | - label: I checked for similar feature requests
14 | required: true
15 | - type: textarea
16 | id: feature-request
17 | attributes:
18 | label: Feature request
19 | description: Please describe what you think should be added to Supabase Kt
20 | validations:
21 | required: true
22 | - type: textarea
23 | id: usecase
24 | attributes:
25 | label: Usecase
26 | description: 'Please provide an use case for your feature request'
27 | validations:
28 | required: false
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.yml:
--------------------------------------------------------------------------------
1 | name: Question
2 | description: Template for questions
3 | title: '[Question]: '
4 | labels: ["question"]
5 | body:
6 | - type: checkboxes
7 | id: general
8 | attributes:
9 | label: General info
10 | options:
11 | - label: I checked the [troubleshooting](https://github.com/supabase-community/supabase-kt/blob/master/TROUBLESHOOTING.md) page for similar problems
12 | required: true
13 | - type: textarea
14 | id: question
15 | attributes:
16 | label: What is your question?
17 | description: Please ask your question
18 | validations:
19 | required: true
20 | - type: textarea
21 | id: logs
22 | attributes:
23 | label: Relevant log output (optional)
24 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
25 | render: shell
26 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gradle" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 | reviewers:
13 | - "jan-tennert"
14 | assignees:
15 | - "jan-tennert"
16 |
--------------------------------------------------------------------------------
/.github/images/desktop_supabase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/.github/images/desktop_supabase.png
--------------------------------------------------------------------------------
/.github/images/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/.github/images/img.png
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build project
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'master'
7 |
8 | concurrency:
9 | group: environment-${{ github.ref }}
10 | cancel-in-progress: true
11 |
12 | jobs:
13 | build:
14 | runs-on: macos-latest
15 | steps:
16 | - name: Checkout sources
17 | uses: actions/checkout@v4
18 | - name: Set up JDK 17
19 | uses: actions/setup-java@v4
20 | with:
21 | java-version: '17'
22 | distribution: 'temurin'
23 | - name: Setup Gradle
24 | uses: gradle/actions/setup-gradle@v4.0.1
25 | with:
26 | cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
27 | cache-read-only: false
28 | - name: Build supabase-kt
29 | run: ./gradlew -DLibrariesOnly=true assemble --stacktrace --configuration-cache --scan
30 |
--------------------------------------------------------------------------------
/.github/workflows/cache.yml:
--------------------------------------------------------------------------------
1 | name: Clear all Github actions caches
2 | on:
3 | workflow_dispatch:
4 |
5 | permissions:
6 | actions: write
7 |
8 | jobs:
9 | clear-cache:
10 | name: Delete all caches
11 | runs-on: ubuntu-20.04
12 | steps:
13 | - name: Clear caches
14 | uses: easimon/wipe-cache@main
15 | with:
16 | github-token: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/labeler.yml:
--------------------------------------------------------------------------------
1 | name: "Pull Request Labeler"
2 | on:
3 | - pull_request_target
4 |
5 | jobs:
6 | labeler:
7 | permissions:
8 | contents: read
9 | pull-requests: write
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/labeler@v5
13 | with:
14 | sync-labels: true
--------------------------------------------------------------------------------
/.github/workflows/samples.yml:
--------------------------------------------------------------------------------
1 | name: Build samples
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - '*'
7 | push:
8 | branches:
9 | - 'master'
10 |
11 | jobs:
12 | build:
13 | strategy:
14 | matrix:
15 | sample: [
16 | 'chat-demo-mpp',
17 | 'file-upload',
18 | 'multi-factor-auth'
19 | ]
20 | runs-on: macos-latest
21 | steps:
22 | - name: Checkout sources
23 | uses: actions/checkout@v4
24 | - name: Set up JDK 17
25 | uses: actions/setup-java@v4
26 | with:
27 | java-version: '17'
28 | distribution: 'temurin'
29 | - name: Setup Gradle
30 | uses: gradle/actions/setup-gradle@v4.0.1
31 | with:
32 | cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
33 | cache-read-only: ${{ github.ref != 'refs/heads/master' }}
34 | - name: Build sample ${{ matrix.sample }}
35 | run: ./gradlew :sample:${{ matrix.sample }}:buildAll --stacktrace --configuration-cache
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | **/.gradle/**
3 | **/build/**
4 | /test/
5 | .idea
6 | local.properties
7 | .kotlin
8 | kotlin-js-store
9 |
--------------------------------------------------------------------------------
/Auth/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/RedirectUrl.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | internal actual fun Auth.defaultPlatformRedirectUrl(): String? = config.deepLinkOrNull
--------------------------------------------------------------------------------
/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/Utils.android.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("RedundantSuspendModifier")
2 | package io.github.jan.supabase.auth
3 |
4 | import android.net.Uri
5 | import io.github.jan.supabase.SupabaseClient
6 | import io.github.jan.supabase.auth.user.UserSession
7 |
8 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
9 | openUrl(Uri.parse(url), auth.config.defaultExternalAuthAction)
10 | }
11 |
12 | internal actual suspend fun Auth.startExternalAuth(
13 | redirectUrl: String?,
14 | getUrl: suspend (redirectTo: String?) -> String,
15 | onSessionSuccess: suspend (UserSession) -> Unit
16 | ) {
17 | config.urlLauncher.openUrl(supabaseClient, getUrl(redirectUrl))
18 | }
--------------------------------------------------------------------------------
/Auth/src/androidMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig: ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/androidUnitTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() {
4 | enableLifecycleCallbacks = false
5 | }
--------------------------------------------------------------------------------
/Auth/src/appleMain/kotlin/io/github/jan/supabase/auth/RedirectUrl.apple.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | internal actual fun Auth.defaultPlatformRedirectUrl(): String? = config.deepLinkOrNull
--------------------------------------------------------------------------------
/Auth/src/appleMain/kotlin/io/github/jan/supabase/auth/Utils.apple.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import io.github.jan.supabase.auth.providers.openUrl
5 | import platform.Foundation.NSURL
6 |
7 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
8 | openUrl(NSURL(string = url))
9 | }
--------------------------------------------------------------------------------
/Auth/src/appleMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig: ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/appleMain/kotlin/io/github/jan/supabase/auth/providers/OAuthProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import platform.Foundation.NSURL
4 |
5 | internal expect fun openUrl(url: NSURL)
--------------------------------------------------------------------------------
/Auth/src/appleMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | actual fun Auth.setupPlatform() = Unit
--------------------------------------------------------------------------------
/Auth/src/appleTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() = Unit
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/JsonUtils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import kotlinx.serialization.json.JsonObjectBuilder
4 | import kotlinx.serialization.json.put
5 | import kotlinx.serialization.json.putJsonObject
6 |
7 | internal fun JsonObjectBuilder.putCaptchaToken(token: String) {
8 | putJsonObject("gotrue_meta_security") {
9 | put("captcha_token", token)
10 | }
11 | }
12 |
13 | internal fun JsonObjectBuilder.putCodeChallenge(codeChallenge: String) {
14 | put("code_challenge", codeChallenge)
15 | put("code_challenge_method", PKCEConstants.CHALLENGE_METHOD)
16 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/MinimalConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | /**
4 | * Applies minimal configuration to the [AuthConfig]. This is useful for server side applications, where you don't need to store the session or code verifier.
5 | * @see AuthConfigDefaults
6 | */
7 | fun AuthConfigDefaults.minimalConfig() {
8 | this.alwaysAutoRefresh = false
9 | this.autoLoadFromStorage = false
10 | this.autoSaveToStorage = false
11 | this.sessionManager = MemorySessionManager()
12 | this.codeVerifierCache = MemoryCodeVerifierCache()
13 | this.enableLifecycleCallbacks = false
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/PKCE.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("MatchingDeclarationName")
2 | package io.github.jan.supabase.auth
3 |
4 | import okio.ByteString.Companion.toByteString
5 | import org.kotlincrypto.random.CryptoRand
6 | import kotlin.io.encoding.Base64
7 | import kotlin.io.encoding.ExperimentalEncodingApi
8 |
9 | internal object PKCEConstants {
10 | const val VERIFIER_LENGTH = 64
11 | const val CHALLENGE_METHOD = "s256"
12 | }
13 |
14 | @OptIn(ExperimentalEncodingApi::class)
15 | internal fun generateCodeVerifier(): String {
16 | val bytes = ByteArray(PKCEConstants.VERIFIER_LENGTH)
17 | CryptoRand.nextBytes(bytes)
18 | return Base64.UrlSafe.encode(bytes)
19 | }
20 |
21 | @OptIn(ExperimentalEncodingApi::class)
22 | internal fun generateCodeChallenge(codeVerifier: String): String {
23 | val byteString = codeVerifier.encodeToByteArray().toByteString()
24 | val hash = byteString.sha256()
25 | return Base64.UrlSafe.encode(hash.toByteArray()).replace("=", "")
26 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/PostgrestFilterDSL.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | /**
4 | * Used to mark Postgrest filter DSL functions
5 | */
6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
7 | @DslMarker
8 | annotation class PostgrestFilterDSL
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/RedirectUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | internal expect fun Auth.defaultPlatformRedirectUrl(): String?
7 |
8 | internal fun Auth.defaultRedirectUrl(): String? {
9 | return config.defaultRedirectUrl ?: defaultPlatformRedirectUrl()
10 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/SignOutScope.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | /**
4 | * Represents the scope of a sign-out action.
5 | *
6 | * The sign-out scope determines the scope of the sign-out action being performed.
7 | */
8 | enum class SignOutScope {
9 | /**
10 | * Sign-out action applies to all sessions across the entire system.
11 | */
12 | GLOBAL,
13 |
14 | /**
15 | * Sign-out action applies only to the current session.
16 | */
17 | LOCAL,
18 |
19 | /**
20 | * Sign-out action applies to other sessions, excluding the current session.
21 | */
22 | OTHERS
23 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/UrlLauncher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import io.github.jan.supabase.annotations.SupabaseExperimental
5 |
6 | /**
7 | * A [UrlLauncher] is used to open a URL in the system browser.
8 | */
9 | @SupabaseExperimental
10 | fun interface UrlLauncher {
11 |
12 | /**
13 | * Open the given URL in the system browser.
14 | * @param url The URL to open.
15 | */
16 | suspend fun openUrl(supabase: SupabaseClient, url: String)
17 |
18 | companion object {
19 |
20 | /**
21 | * Default implementation of [UrlLauncher] that opens the URL in the system browser.
22 | */
23 | val DEFAULT = UrlLauncher { supabase, url ->
24 | supabase.openExternalUrl(url)
25 | }
26 |
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import io.github.jan.supabase.auth.user.UserSession
5 |
6 | internal fun invalidArg(message: String): Nothing = throw IllegalArgumentException(message)
7 |
8 | internal expect suspend fun SupabaseClient.openExternalUrl(url: String)
9 |
10 | internal expect suspend fun Auth.startExternalAuth(
11 | redirectUrl: String?,
12 | getUrl: suspend (redirectTo: String?) -> String,
13 | onSessionSuccess: suspend (UserSession) -> Unit
14 | )
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthSessionMissingException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.exception
2 |
3 | import io.ktor.client.statement.HttpResponse
4 |
5 | /**
6 | * Exception thrown when a session is not found.
7 | */
8 | class AuthSessionMissingException(response: HttpResponse): AuthRestException(
9 | errorCode = CODE,
10 | response = response,
11 | errorDescription = "Session not found. This can happen if the user was logged out or deleted."
12 | ) {
13 |
14 | internal companion object {
15 | const val CODE = "session_not_found"
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/exception/AuthWeakPasswordException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.exception
2 |
3 | import io.ktor.client.statement.HttpResponse
4 |
5 | /**
6 | * Exception thrown on sign-up if the password is too weak
7 | * @param description The description of the exception.
8 | * @param reasons The reasons why the password is weak.
9 | */
10 | class AuthWeakPasswordException(
11 | description: String,
12 | response: HttpResponse,
13 | val reasons: List
14 | ) : AuthRestException(
15 | CODE,
16 | description,
17 | response
18 | ) {
19 |
20 | internal companion object {
21 | const val CODE = "weak_password"
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/mfa/MfaChallenge.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.mfa
2 |
3 | import kotlinx.datetime.Instant
4 | import kotlinx.serialization.SerialName
5 | import kotlinx.serialization.Serializable
6 |
7 | /**
8 | * A challenge to verify the user's identity.
9 | * @property id The id of the challenge.
10 | * @property factorType Factor Type which generated the challenge.
11 | */
12 | @Serializable
13 | data class MfaChallenge(val id: String, @SerialName("type") val factorType: String) {
14 |
15 | @SerialName("expires_at") private val expiresAtSeconds: Long = 0
16 |
17 | /**
18 | * Timestamp in UNIX seconds when this challenge will no longer be usable.
19 | */
20 | val expiresAt: Instant
21 | get() = Instant.fromEpochSeconds(expiresAtSeconds)
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/mfa/MfaFactor.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.mfa
2 |
3 | /**
4 | * Represents an enrolled MFA Factor
5 | * @param id The ID of the factor
6 | * @param type The type of the factor
7 | * @param data Additional data of the factor (like QR-Code for TOTP)
8 | */
9 | data class MfaFactor(
10 | val id: String,
11 | val type: String,
12 | val data: T
13 | )
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/mfa/MfaStatus.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.mfa
2 |
3 | /**
4 | * Represents the MFA status of a user.
5 | * @property enabled Whether MFA is enabled for the user. If true, the user can log in using MFA and has at least one verified factor.
6 | * @property active Whether MFA is active for the user. If true, the user is logged in using MFA.
7 | */
8 | data class MfaStatus(
9 | val enabled: Boolean,
10 | val active: Boolean
11 | )
12 |
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import io.github.jan.supabase.auth.Auth
4 |
5 | /**
6 | * Configuration for external authentication providers like Google, Twitter, etc.
7 | */
8 | expect class ExternalAuthConfig(): ExternalAuthConfigDefaults
9 |
10 | /**
11 | * The default values for [ExternalAuthConfig]
12 | */
13 | open class ExternalAuthConfigDefaults {
14 |
15 | /**
16 | * The scopes to request from the external provider
17 | */
18 | val scopes = mutableListOf()
19 |
20 | /**
21 | * Additional query parameters to send to the external provider
22 | */
23 | val queryParams = mutableMapOf()
24 |
25 | /**
26 | * Automatically open the URL in the browser. Only applies to [Auth.linkIdentity].
27 | */
28 | var automaticallyOpenUrl: Boolean = true
29 |
30 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/status/RefreshFailureCause.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.status
2 |
3 | import io.github.jan.supabase.exceptions.RestException
4 |
5 | /**
6 | * Represents the cause of a refresh error
7 | */
8 | //Note: Move this interface when removing the deprecated property from [SessionStatus.RefreshFailure]
9 | sealed interface RefreshFailureCause {
10 |
11 | /**
12 | * The refresh failed due to a network error
13 | * @param exception The exception that caused the error
14 | */
15 | data class NetworkError(val exception: Throwable) : RefreshFailureCause
16 |
17 | /**
18 | * The refresh failed due to an internal server error
19 | * @param exception The rest exception that caused the error
20 | */
21 | data class InternalServerError(val exception: RestException) : RefreshFailureCause
22 |
23 | }
--------------------------------------------------------------------------------
/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/user/Identity.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UndocumentedPublicClass", "UndocumentedPublicFunction", "UndocumentedPublicProperty")
2 | package io.github.jan.supabase.auth.user
3 |
4 |
5 | import kotlinx.serialization.SerialName
6 | import kotlinx.serialization.Serializable
7 | import kotlinx.serialization.json.JsonObject
8 |
9 | @Serializable
10 | data class Identity(
11 | @SerialName("id")
12 | val id: String,
13 | @SerialName("identity_data")
14 | val identityData: JsonObject,
15 | @SerialName("identity_id")
16 | val identityId: String? = null,
17 | @SerialName("last_sign_in_at")
18 | val lastSignInAt: String? = null,
19 | @SerialName("updated_at")
20 | val updatedAt: String? = null,
21 | @SerialName("created_at")
22 | val createdAt: String? = null,
23 | @SerialName("provider")
24 | val provider: String,
25 | @SerialName("user_id")
26 | val userId: String
27 | )
--------------------------------------------------------------------------------
/Auth/src/commonTest/kotlin/AuthTestUtils.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.Auth
2 | import io.github.jan.supabase.auth.status.SessionStatus
3 |
4 | fun Auth.sessionSource() = (sessionStatus.value as SessionStatus.Authenticated).source
5 |
6 | inline fun Auth.sessionSourceAs() = sessionSource() as T
--------------------------------------------------------------------------------
/Auth/src/commonTest/kotlin/CodeVerifierCacheTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.MemoryCodeVerifierCache
2 | import kotlinx.coroutines.test.runTest
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 | import kotlin.test.assertNull
6 |
7 | class CodeVerifierCacheTest {
8 |
9 | @Test
10 | fun testMemoryCodeVerifierCache() {
11 | runTest {
12 | val codeVerifier = "codeVerifier"
13 | val codeVerifierCache = MemoryCodeVerifierCache(codeVerifier)
14 | assertEquals(codeVerifier, codeVerifierCache.loadCodeVerifier())
15 | val newCodeVerifier = "newCodeVerifier"
16 | codeVerifierCache.saveCodeVerifier(newCodeVerifier)
17 | assertEquals(newCodeVerifier, codeVerifierCache.loadCodeVerifier())
18 | codeVerifierCache.deleteCodeVerifier()
19 | assertNull(codeVerifierCache.loadCodeVerifier())
20 | }
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/Auth/src/desktopMain/kotlin/io/github/jan/supabase/auth/Utils.desktop.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.auth.server.createServer
4 | import io.github.jan.supabase.auth.user.UserSession
5 | import kotlinx.coroutines.Dispatchers
6 | import kotlinx.coroutines.IO
7 | import kotlinx.coroutines.withContext
8 |
9 | internal actual suspend fun Auth.startExternalAuth(
10 | redirectUrl: String?,
11 | getUrl: suspend (redirectTo: String?) -> String,
12 | onSessionSuccess: suspend (UserSession) -> Unit
13 | ) {
14 | withContext(Dispatchers.IO) {
15 | if(redirectUrl != null) {
16 | config.urlLauncher.openUrl(supabaseClient, getUrl(redirectUrl))
17 | return@withContext
18 | }
19 | createServer({
20 | getUrl(it)
21 | }, supabaseClient.auth, onSessionSuccess)
22 | }
23 | }
--------------------------------------------------------------------------------
/Auth/src/iosMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.plugins.CustomSerializationConfig
4 |
5 | /**
6 | * The configuration for [Auth]
7 | */
8 | actual class AuthConfig : CustomSerializationConfig, AuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/iosMain/kotlin/io/github/jan/supabase/auth/providers/openUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import io.github.jan.supabase.auth.Auth
4 | import io.github.jan.supabase.logging.d
5 | import io.github.jan.supabase.logging.e
6 | import platform.Foundation.NSURL
7 | import platform.UIKit.UIApplication
8 |
9 | internal actual fun openUrl(url: NSURL) {
10 | UIApplication.sharedApplication.openURL(url, emptyMap()) {
11 | if(it) Auth.logger.d { "Successfully opened provider url in safari" } else Auth.logger.e { "Failed to open provider url in safari" }
12 | }
13 | }
--------------------------------------------------------------------------------
/Auth/src/jsMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.plugins.CustomSerializationConfig
4 |
5 | /**
6 | * The configuration for [Auth]
7 | */
8 | actual class AuthConfig : CustomSerializationConfig, AuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/jsMain/kotlin/io/github/jan/supabase/auth/RedirectUrl.js.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.browser.window
5 |
6 | @SupabaseInternal
7 | internal actual fun Auth.defaultPlatformRedirectUrl(): String? = window.location.origin
--------------------------------------------------------------------------------
/Auth/src/jsMain/kotlin/io/github/jan/supabase/auth/Utils.js.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import kotlinx.browser.window
5 |
6 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
7 | window.location.href = url
8 | }
--------------------------------------------------------------------------------
/Auth/src/jsMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig: ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/jsTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() = Unit
--------------------------------------------------------------------------------
/Auth/src/jvmMain/kotlin/io/github/jan/supabase/auth/RedirectUrl.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | internal actual fun Auth.defaultPlatformRedirectUrl(): String? = null
--------------------------------------------------------------------------------
/Auth/src/jvmMain/kotlin/io/github/jan/supabase/auth/Utils.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import kotlinx.coroutines.Dispatchers
5 | import kotlinx.coroutines.withContext
6 | import java.awt.Desktop
7 | import java.net.URI
8 |
9 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
10 | withContext(Dispatchers.IO) {
11 | Desktop.getDesktop()
12 | .browse(URI(url))
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Auth/src/jvmMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig: ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/jvmMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | actual fun Auth.setupPlatform() = Unit
--------------------------------------------------------------------------------
/Auth/src/jvmTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() = Unit
--------------------------------------------------------------------------------
/Auth/src/linuxMain/kotlin/io/github/jan/supabase/auth/SettingsUtil.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | actual fun Auth.createDefaultSessionManager(): SessionManager = MemorySessionManager()
7 |
8 | @SupabaseInternal
9 | actual fun Auth.createDefaultCodeVerifierCache(): CodeVerifierCache = MemoryCodeVerifierCache()
--------------------------------------------------------------------------------
/Auth/src/linuxMain/kotlin/io/github/jan/supabase/auth/Utils.linux.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import platform.posix.system
5 |
6 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
7 | system("xdg-open $url")
8 | }
--------------------------------------------------------------------------------
/Auth/src/linuxMain/kotlin/io/github/jan/supabase/auth/generateRedirectUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | internal actual fun Auth.defaultPlatformRedirectUrl(): String? = null
--------------------------------------------------------------------------------
/Auth/src/linuxMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig: ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/linuxMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import io.github.jan.supabase.logging.w
5 |
6 | @SupabaseInternal
7 | actual fun Auth.setupPlatform() {
8 | Auth.logger.w { "Linux support is experimental, please report any bugs you find!" }
9 | }
--------------------------------------------------------------------------------
/Auth/src/linuxTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() = Unit
--------------------------------------------------------------------------------
/Auth/src/macosMain/kotlin/io/github/jan/supabase/auth/providers/openUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import io.github.jan.supabase.auth.Auth
4 | import io.github.jan.supabase.logging.d
5 | import io.github.jan.supabase.logging.e
6 | import platform.AppKit.NSWorkspace
7 | import platform.AppKit.NSWorkspaceOpenConfiguration
8 | import platform.Foundation.NSURL
9 |
10 | internal actual fun openUrl(url: NSURL) {
11 | NSWorkspace.sharedWorkspace().openURL(url, NSWorkspaceOpenConfiguration()) { _, error ->
12 | if(error != null) Auth.logger.d { "Successfully opened provider url in safari" } else Auth.logger.e { "Failed to open provider url in safari" }
13 | }
14 | }
--------------------------------------------------------------------------------
/Auth/src/mingwMain/kotlin/io/github/jan/supabase/auth/Utils.mingw.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import kotlinx.cinterop.ExperimentalForeignApi
5 | import platform.windows.SW_SHOWNORMAL
6 | import platform.windows.ShellExecuteW
7 |
8 | @OptIn(ExperimentalForeignApi::class)
9 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
10 | ShellExecuteW(null, "open", url, null, null, SW_SHOWNORMAL);
11 | }
--------------------------------------------------------------------------------
/Auth/src/mingwMain/kotlin/io/github/jan/supabase/auth/generateRedirectUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | internal actual fun Auth.defaultPlatformRedirectUrl(): String? = null
--------------------------------------------------------------------------------
/Auth/src/mingwMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig :
7 | ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/mingwMain/kotlin/io/github/jan/supabase/auth/setupPlatform.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import io.github.jan.supabase.logging.w
5 |
6 | @SupabaseInternal
7 | actual fun Auth.setupPlatform() {
8 | Auth.logger.w { "Windows support is experimental, please report any bugs you find!" }
9 | }
--------------------------------------------------------------------------------
/Auth/src/mingwTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() = Unit
--------------------------------------------------------------------------------
/Auth/src/nonDesktopMain/kotlin/io/github/jan/supabase/auth/Utils.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("RedundantSuspendModifier")
2 | package io.github.jan.supabase.auth
3 |
4 | import io.github.jan.supabase.auth.user.UserSession
5 |
6 | internal actual suspend fun Auth.startExternalAuth(
7 | redirectUrl: String?,
8 | getUrl: suspend (redirectTo: String?) -> String,
9 | onSessionSuccess: suspend (UserSession) -> Unit
10 | ) {
11 | config.urlLauncher.openUrl(supabaseClient, getUrl(redirectUrl))
12 | }
--------------------------------------------------------------------------------
/Auth/src/settingsTest/kotlin/SettingsTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.createDefaultSettingsKey
2 | import kotlin.test.Test
3 | import kotlin.test.assertEquals
4 |
5 | class SettingsTest {
6 |
7 | @Test
8 | fun testSettingsKey() {
9 | val supabaseUrl = "id.supabase.co"
10 | val key = createDefaultSettingsKey(supabaseUrl)
11 | assertEquals("sb-id-supabase-co", key)
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/Auth/src/tvosMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.plugins.CustomSerializationConfig
4 |
5 | /**
6 | * The configuration for [Auth]
7 | */
8 | actual class AuthConfig : CustomSerializationConfig, AuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/tvosMain/kotlin/io/github/jan/supabase/auth/providers/openUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import platform.Foundation.NSURL
4 |
5 | internal actual fun openUrl(url: NSURL) {
6 | error("Can't open url on tvOS")
7 | }
--------------------------------------------------------------------------------
/Auth/src/wasmJsMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.plugins.CustomSerializationConfig
4 |
5 | /**
6 | * The configuration for [Auth]
7 | */
8 | actual class AuthConfig: CustomSerializationConfig, AuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/wasmJsMain/kotlin/io/github/jan/supabase/auth/RedirectUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.browser.window
5 |
6 | @SupabaseInternal
7 | actual fun Auth.defaultPlatformRedirectUrl(): String? = window.location.origin
--------------------------------------------------------------------------------
/Auth/src/wasmJsMain/kotlin/io/github/jan/supabase/auth/Utils.wasmJs.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 | import kotlinx.browser.window
5 |
6 | internal actual suspend fun SupabaseClient.openExternalUrl(url: String) {
7 | window.location.href = url
8 | }
--------------------------------------------------------------------------------
/Auth/src/wasmJsMain/kotlin/io/github/jan/supabase/auth/providers/ExternalAuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | /**
4 | * Configuration for external authentication providers like Google, Twitter, etc.
5 | */
6 | actual class ExternalAuthConfig: ExternalAuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/wasmJsTest/kotlin/platformSettings.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.auth.AuthConfig
2 |
3 | actual fun AuthConfig.platformSettings() = Unit
--------------------------------------------------------------------------------
/Auth/src/watchosMain/kotlin/io/github/jan/supabase/auth/AuthConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth
2 |
3 | import io.github.jan.supabase.plugins.CustomSerializationConfig
4 |
5 | /**
6 | * The configuration for [Auth]
7 | */
8 | actual class AuthConfig : CustomSerializationConfig, AuthConfigDefaults()
--------------------------------------------------------------------------------
/Auth/src/watchosMain/kotlin/io/github/jan/supabase/auth/providers/openUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.auth.providers
2 |
3 | import platform.Foundation.NSURL
4 |
5 | internal actual fun openUrl(url: NSURL) {
6 | error("Can't open url on watchOS")
7 | }
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @jan-tennert
2 |
--------------------------------------------------------------------------------
/Functions/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Functions/src/commonMain/kotlin/io/github/jan/supabase/functions/FunctionRegion.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("UndocumentedPublicProperty")
2 | package io.github.jan.supabase.functions
3 |
4 | /**
5 | * The region where the function is invoked.
6 | * @param value The value of the region
7 | */
8 | enum class FunctionRegion(val value: String) {
9 | ANY("any"),
10 | AP_NORTHEAST_1("ap-northeast-1"),
11 | AP_NORTHEAST_2("ap-northeast-2"),
12 | AP_SOUTH_1("ap-south-1"),
13 | AP_SOUTHEAST_1("ap-southeast-1"),
14 | AP_SOUTHEAST_2("ap-southeast-2"),
15 | CA_CENTRAL_1("ca-central-1"),
16 | EU_CENTRAL_1("eu-central-1"),
17 | EU_WEST_1("eu-west-1"),
18 | EU_WEST_2("eu-west-2"),
19 | EU_WEST_3("eu-west-3"),
20 | SA_EAST_1("sa-east-1"),
21 | US_EAST_1("us-east-1"),
22 | US_WEST_1("us-west-1"),
23 | US_WEST_2("us-west-2"),
24 | }
--------------------------------------------------------------------------------
/Postgrest/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Postgrest Client"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | defaultConfig()
15 | allTargets()
16 | sourceSets {
17 | val commonMain by getting {
18 | dependencies {
19 | addModules(SupabaseModule.AUTH)
20 | api(libs.kotlin.reflect)
21 | }
22 | }
23 | val commonTest by getting {
24 | dependencies {
25 | implementation(libs.bundles.testing)
26 | implementation(project(":test-common"))
27 | }
28 | }
29 | }
30 | }
31 |
32 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/Postgrest/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Postgrest/src/androidMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.SerialName
5 | import kotlin.reflect.KProperty1
6 | import kotlin.reflect.full.findAnnotation
7 |
8 | @SupabaseInternal
9 | actual fun getSerialName(property: KProperty1): String {
10 | val serialName = property.findAnnotation()
11 | return serialName?.value ?: property.name
12 | }
13 |
--------------------------------------------------------------------------------
/Postgrest/src/appleMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlin.reflect.KProperty1
5 |
6 | @SupabaseInternal
7 | actual fun getSerialName(property: KProperty1) = property.name
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestDsl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @DslMarker
6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
7 | @SupabaseInternal
8 | annotation class PostgrestDsl
9 |
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/PostgrestErrorResponse.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | internal data class PostgrestErrorResponse(
7 | val message: String,
8 | val hint: String? = null,
9 | val details: String? = null,
10 | val code: String? = null,
11 | )
12 |
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/exception/PostgrestRestException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.exception
2 |
3 | import io.github.jan.supabase.exceptions.RestException
4 | import io.ktor.client.statement.HttpResponse
5 |
6 | /**
7 | * Exception thrown when a Postgrest request fails
8 | * @param message The error message
9 | * @param hint A hint to the error
10 | * @param details Additional details about the error
11 | * @param code The error code
12 | * @param response The response that caused the exception
13 | */
14 | class PostgrestRestException(
15 | message: String,
16 | val hint: String?,
17 | val details: String?,
18 | val code: String?,
19 | response: HttpResponse
20 | ): RestException(message, hint ?: details, response)
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/executor/RequestExecutor.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.executor
2 |
3 | import io.github.jan.supabase.postgrest.Postgrest
4 | import io.github.jan.supabase.postgrest.request.PostgrestRequest
5 | import io.github.jan.supabase.postgrest.result.PostgrestResult
6 |
7 | /**
8 | * Request executor interface
9 | *
10 | */
11 | sealed interface RequestExecutor {
12 |
13 | /**
14 | * Execute given PostgrestRequest
15 | *
16 | * @param path [String]
17 | * @param request [PostgrestRequest]
18 | * @return [PostgrestResult]
19 | */
20 | suspend fun execute(postgrest: Postgrest, path: String, request: PostgrestRequest): PostgrestResult
21 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/executor/RestRequestExecutor.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.executor
2 |
3 | import io.github.jan.supabase.postgrest.Postgrest
4 | import io.github.jan.supabase.postgrest.PostgrestImpl
5 | import io.github.jan.supabase.postgrest.request.PostgrestRequest
6 | import io.github.jan.supabase.postgrest.result.PostgrestResult
7 |
8 | @PublishedApi
9 | internal data object RestRequestExecutor : RequestExecutor {
10 |
11 | override suspend fun execute(
12 | postgrest: Postgrest,
13 | path: String,
14 | request: PostgrestRequest
15 | ): PostgrestResult {
16 | val authenticatedSupabaseApi = (postgrest as PostgrestImpl).api
17 | return authenticatedSupabaseApi.request(path) {
18 | configurePostgrestRequest(request)
19 | }.asPostgrestResult(postgrest)
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/Order.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query
2 |
3 | /**
4 | * Used to order the result of a query
5 | * @param value The value to be used in the query
6 | */
7 | enum class Order(val value: String) {
8 | /**
9 | * Order the data ascending
10 | */
11 | ASCENDING("asc"),
12 |
13 | /**
14 | * Order the data descending
15 | */
16 | DESCENDING("desc");
17 | }
18 |
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/filter/FilterOperation.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 | package io.github.jan.supabase.postgrest.query.filter
7 |
8 | /**
9 | * Represents a filter operation for a column using a specific operator and a value.
10 | */
11 | data class FilterOperation(val column: String, val operator: FilterOperator, val value: Any)
12 |
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/filter/FilterOperator.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 | package io.github.jan.supabase.postgrest.query.filter
7 |
8 | /**
9 | * Represents a single filter operation
10 | */
11 | enum class FilterOperator(val identifier: String) {
12 | EQ("eq"),
13 | NEQ("neq"),
14 | GT("gt"),
15 | GTE("gte"),
16 | LT("lt"),
17 | LTE("lte"),
18 | LIKE("like"),
19 | MATCH("match"),
20 | ILIKE("ilike"),
21 | IMATCH("imatch"),
22 | IS("is"),
23 | IN("in"),
24 | CS("cs"),
25 | CD("cd"),
26 | SL("sl"),
27 | SR("sr"),
28 | NXL("nxl"),
29 | NXR("nxr"),
30 | ADJ("adj"),
31 | OV("ov"),
32 | FTS("fts"),
33 | PLFTS("plfts"),
34 | PHFTS("phfts"),
35 | WFTS("wfts"),
36 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/filter/TextSearchType.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 | package io.github.jan.supabase.postgrest.query.filter
7 |
8 | /**
9 | * Used to search rows using a full text search. See [Postgrest](https://postgrest.org/en/stable/api.html#full-text-search) for more information
10 | */
11 | enum class TextSearchType(val identifier: String) {
12 | NONE(""),
13 | PLAINTO("pl"),
14 | PHRASETO("ph"),
15 | WEBSEARCH("w")
16 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/InsertRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
4 | import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder
5 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
6 |
7 | /**
8 | * Request builder for [PostgrestQueryBuilder.insert]
9 | */
10 | open class InsertRequestBuilder(propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) {
11 |
12 | /**
13 | * Make missing fields default to `null`.
14 | * Otherwise, use the default value for the column. This only applies when
15 | * inserting new rows, not when merging with existing rows under
16 | */
17 | var defaultToNull: Boolean = true
18 |
19 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/RpcRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.Postgrest
4 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
5 | import io.github.jan.supabase.postgrest.RpcMethod
6 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
7 |
8 | /**
9 | * Request builder for [Postgrest.rpc]
10 | */
11 | class RpcRequestBuilder(defaultSchema: String, propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) {
12 |
13 | /**
14 | * The HTTP method to use. Default is POST
15 | */
16 | var method: RpcMethod = RpcMethod.POST
17 |
18 | /**
19 | * The database schema
20 | */
21 | var schema: String = defaultSchema
22 |
23 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/SelectRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
4 | import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder
5 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
6 |
7 | /**
8 | * Request builder for [PostgrestQueryBuilder.select]
9 | */
10 | class SelectRequestBuilder(propertyConversionMethod: PropertyConversionMethod): PostgrestRequestBuilder(propertyConversionMethod) {
11 |
12 | /**
13 | * If true, no body will be returned. Useful when using count.
14 | */
15 | var head: Boolean = false
16 |
17 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/query/request/UpsertRequestBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.query.request
2 |
3 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
4 | import io.github.jan.supabase.postgrest.query.PostgrestQueryBuilder
5 |
6 | /**
7 | * Request builder for [PostgrestQueryBuilder.upsert]
8 | */
9 | class UpsertRequestBuilder(propertyConversionMethod: PropertyConversionMethod): InsertRequestBuilder(propertyConversionMethod) {
10 |
11 | /**
12 | * Comma-separated UNIQUE column(s) to specify how
13 | * duplicate rows are determined. Two rows are duplicates if all the
14 | * `onConflict` columns are equal.
15 | */
16 | var onConflict: String? = null
17 |
18 | /**
19 | * If `true`, duplicate rows are ignored. If `false`, duplicate rows are merged with existing rows.
20 | */
21 | var ignoreDuplicates: Boolean = false
22 |
23 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/DeleteRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.github.jan.supabase.postgrest.query.Returning
5 | import io.ktor.http.Headers
6 | import io.ktor.http.HttpMethod
7 |
8 | @PublishedApi
9 | internal class DeleteRequest(
10 | override val returning: Returning = Returning.Minimal,
11 | private val count: Count? = null,
12 | override val urlParams: Map,
13 | override val schema: String,
14 | override val headers: Headers = Headers.Empty,
15 | ) : PostgrestRequest {
16 |
17 | override val method = HttpMethod.Delete
18 | override val prefer = buildList {
19 | add("return=${returning.identifier}")
20 | if (count != null) add("count=${count.identifier}")
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/PostgrestRequest.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress(
2 | "UndocumentedPublicClass",
3 | "UndocumentedPublicFunction",
4 | "UndocumentedPublicProperty"
5 | )
6 |
7 | package io.github.jan.supabase.postgrest.request
8 |
9 | import io.github.jan.supabase.annotations.SupabaseInternal
10 | import io.github.jan.supabase.postgrest.query.Returning
11 | import io.ktor.http.Headers
12 | import io.ktor.http.HttpMethod
13 | import kotlinx.serialization.json.JsonElement
14 |
15 | @SupabaseInternal
16 | sealed interface PostgrestRequest {
17 |
18 | val body: JsonElement? get() = null
19 | val method: HttpMethod
20 | val urlParams: Map
21 | val headers: Headers get() = Headers.Empty
22 | val returning: Returning get() = Returning.Minimal
23 | val prefer: List
24 | val schema: String
25 |
26 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/RpcRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.ktor.http.Headers
5 | import io.ktor.http.HttpMethod
6 | import kotlinx.serialization.json.JsonElement
7 |
8 | @PublishedApi
9 | internal class RpcRequest(
10 | override val method: HttpMethod,
11 | val count: Count? = null,
12 | override val urlParams: Map,
13 | override val body: JsonElement? = null,
14 | override val schema: String = "public",
15 | override val headers: Headers = Headers.Empty
16 | ) : PostgrestRequest {
17 |
18 | override val prefer = if (count != null) listOf("count=${count.identifier}") else listOf()
19 |
20 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/SelectRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.ktor.http.Headers
5 | import io.ktor.http.HttpMethod
6 |
7 | @PublishedApi
8 | internal class SelectRequest(
9 | val head: Boolean = false,
10 | val count: Count? = null,
11 | override val urlParams: Map,
12 | override val schema: String,
13 | override val headers: Headers = Headers.Empty,
14 | ): PostgrestRequest {
15 |
16 | override val method = if (head) HttpMethod.Head else HttpMethod.Get
17 | override val prefer = if (count != null) listOf("count=${count.identifier}") else listOf()
18 |
19 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonMain/kotlin/io/github/jan/supabase/postgrest/request/UpdateRequest.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest.request
2 |
3 | import io.github.jan.supabase.postgrest.query.Count
4 | import io.github.jan.supabase.postgrest.query.Returning
5 | import io.ktor.http.Headers
6 | import io.ktor.http.HttpMethod
7 | import kotlinx.serialization.json.JsonElement
8 |
9 | @PublishedApi
10 | internal class UpdateRequest(
11 | override val returning: Returning = Returning.Minimal,
12 | private val count: Count? = null,
13 | override val urlParams: Map,
14 | override val body: JsonElement,
15 | override val schema: String,
16 | override val headers: Headers = Headers.Empty,
17 | ) : PostgrestRequest {
18 |
19 | override val method = HttpMethod.Patch
20 | override val prefer = buildList {
21 | add("return=${returning.identifier}")
22 | if (count != null) add("count=${count.identifier}")
23 | }
24 |
25 | }
--------------------------------------------------------------------------------
/Postgrest/src/commonTest/kotlin/Utils.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.annotations.SupabaseInternal
2 | import io.github.jan.supabase.postgrest.PropertyConversionMethod
3 | import io.github.jan.supabase.postgrest.query.PostgrestRequestBuilder
4 |
5 | @SupabaseInternal
6 | inline fun postgrestRequest(propertyConversionMethod: PropertyConversionMethod = PropertyConversionMethod.CAMEL_CASE_TO_SNAKE_CASE, block: PostgrestRequestBuilder.() -> Unit): PostgrestRequestBuilder {
7 | val filter = PostgrestRequestBuilder(propertyConversionMethod)
8 | filter.block()
9 | return filter
10 | }
--------------------------------------------------------------------------------
/Postgrest/src/jsMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlin.reflect.KProperty1
5 |
6 | @SupabaseInternal
7 | actual fun getSerialName(property: KProperty1) = property.name
8 |
--------------------------------------------------------------------------------
/Postgrest/src/jvmMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.SerialName
5 | import kotlin.reflect.KProperty1
6 | import kotlin.reflect.full.findAnnotation
7 |
8 | @SupabaseInternal
9 | actual fun getSerialName(property: KProperty1): String {
10 | val serialName = property.findAnnotation()
11 | return serialName?.value ?: property.name
12 | }
13 |
--------------------------------------------------------------------------------
/Postgrest/src/linuxX64Main/kotlin/io/github/jan/supabase/postgrest/getSerialName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlin.reflect.KProperty1
5 |
6 | @SupabaseInternal
7 | actual fun getSerialName(property: KProperty1): String = property.name
--------------------------------------------------------------------------------
/Postgrest/src/mingwX64Main/kotlin/io/github/jan/supabase/postgrest/getSerialName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlin.reflect.KProperty1
5 |
6 | @SupabaseInternal
7 | actual fun getSerialName(property: KProperty1): String = property.name
--------------------------------------------------------------------------------
/Postgrest/src/wasmJsMain/kotlin/io/github/jan/supabase/postgrest/getColumnName.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.postgrest
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlin.reflect.KProperty1
5 |
6 | @SupabaseInternal
7 | actual fun getSerialName(property: KProperty1) = property.name
8 |
--------------------------------------------------------------------------------
/Realtime/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Realtime Client"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | defaultConfig()
15 | allTargets()
16 | sourceSets {
17 | val commonMain by getting {
18 | dependencies {
19 | addModules(SupabaseModule.AUTH)
20 | api(project(":postgrest-kt"))
21 | api(libs.ktor.client.websockets)
22 | }
23 | }
24 | val commonTest by getting {
25 | dependencies {
26 | implementation(project(":test-common"))
27 | implementation(libs.bundles.testing)
28 | implementation(libs.turbine)
29 | }
30 | }
31 | }
32 | }
33 |
34 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/Realtime/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/RealtimeCallback.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.json.JsonObject
5 |
6 | @SupabaseInternal
7 | sealed interface RealtimeCallback {
8 |
9 | val callback: (T) -> Unit
10 | val id: Long
11 |
12 | class PostgresCallback(
13 | override val callback: (PostgresAction) -> Unit,
14 | val filter: PostgresJoinConfig,
15 | override val id: Long
16 | ): RealtimeCallback
17 |
18 | class BroadcastCallback(
19 | override val callback: (JsonObject) -> Unit,
20 | val event: String,
21 | override val id: Long
22 | ): RealtimeCallback
23 |
24 | class PresenceCallback(
25 | override val callback: (PresenceAction) -> Unit,
26 | override val id: Long
27 | ): RealtimeCallback
28 |
29 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/RealtimeMessage.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonObject
6 |
7 | /**
8 | * Represents a message retrieved by the [RealtimeChannel]
9 | */
10 | @Serializable
11 | @SupabaseInternal
12 | data class RealtimeMessage(val topic: String, val event: String, val payload: JsonObject, val ref: String?)
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/RealtimeTopic.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime
2 |
3 | @PublishedApi
4 | internal object RealtimeTopic {
5 |
6 | const val PREFIX = "realtime"
7 |
8 | fun withChannelId(channelId: String): String {
9 | return "$PREFIX:$channelId"
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/annotations/ChannelDsl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.annotations
2 |
3 | /**
4 | * Used to mark Channel DSL functions
5 | */
6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
7 | @DslMarker
8 | annotation class ChannelDsl
9 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/data/BroadcastApiBody.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.data
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonObject
6 |
7 | @Serializable
8 | internal data class BroadcastApiBody(
9 | val messages: List
10 | )
11 |
12 | @Serializable
13 | internal data class BroadcastApiMessage(
14 | val topic: String,
15 | val event: String,
16 | val payload: JsonObject,
17 | @SerialName("private")
18 | val isPrivate: Boolean
19 | )
20 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/data/PostgresActionData.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.data
2 |
3 | import io.github.jan.supabase.realtime.Column
4 | import kotlinx.datetime.Instant
5 | import kotlinx.serialization.SerialName
6 | import kotlinx.serialization.Serializable
7 | import kotlinx.serialization.json.JsonObject
8 |
9 | @Serializable
10 | internal data class PostgresActionData(
11 | val record: JsonObject? = null,
12 | @SerialName("old_record")
13 | val oldRecord: JsonObject? = null,
14 | val columns: List,
15 | @SerialName("commit_timestamp")
16 | val commitTimestamp: Instant
17 | )
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RBroadcastEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.realtime.RealtimeChannel
4 | import io.github.jan.supabase.realtime.RealtimeMessage
5 | import kotlinx.serialization.json.JsonObject
6 | import kotlinx.serialization.json.jsonObject
7 | import kotlinx.serialization.json.jsonPrimitive
8 |
9 | /**
10 | * Handles broadcast events
11 | */
12 | data object RBroadcastEvent : RealtimeEvent {
13 |
14 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
15 | val event = message.payload["event"]?.jsonPrimitive?.content ?: ""
16 | channel.callbackManager.triggerBroadcast(event, message.payload["payload"]?.jsonObject ?: JsonObject(mutableMapOf()))
17 | }
18 |
19 | override fun appliesTo(message: RealtimeMessage): Boolean {
20 | return message.event == RealtimeChannel.CHANNEL_EVENT_BROADCAST
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RCloseEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.logging.d
4 | import io.github.jan.supabase.realtime.Realtime
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 |
8 | /**
9 | * Event that handles the closing of a channel
10 | */
11 | data object RCloseEvent : RealtimeEvent {
12 |
13 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
14 | channel.realtime.removeChannel(channel)
15 | Realtime.logger.d { "Unsubscribed from channel ${message.topic}" }
16 | }
17 |
18 | override fun appliesTo(message: RealtimeMessage): Boolean {
19 | return message.event == RealtimeChannel.CHANNEL_EVENT_CLOSE
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RErrorEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.logging.e
4 | import io.github.jan.supabase.realtime.Realtime
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 |
8 | /**
9 | * Event that handles an error event
10 | */
11 | data object RErrorEvent : RealtimeEvent {
12 |
13 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
14 | Realtime.logger.e { "Received an error in channel ${message.topic}. That could be as a result of an invalid access token" }
15 | }
16 |
17 | override fun appliesTo(message: RealtimeMessage): Boolean {
18 | return message.event == RealtimeChannel.CHANNEL_EVENT_ERROR
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RPresenceStateEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.decodeIfNotEmptyOrDefault
4 | import io.github.jan.supabase.realtime.Presence
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 |
8 | /**
9 | * Event that handles the presence state event
10 | */
11 | data object RPresenceStateEvent : RealtimeEvent {
12 |
13 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
14 | val joins = message.payload.decodeIfNotEmptyOrDefault(mapOf())
15 | channel.callbackManager.triggerPresenceDiff(joins, mapOf())
16 | }
17 |
18 | override fun appliesTo(message: RealtimeMessage): Boolean {
19 | return message.event == RealtimeChannel.CHANNEL_EVENT_PRESENCE_STATE
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RSystemEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.logging.d
4 | import io.github.jan.supabase.realtime.Realtime
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 | import kotlinx.serialization.json.jsonPrimitive
8 |
9 | /**
10 | * Event that handles the system event
11 | */
12 | data object RSystemEvent : RealtimeEvent {
13 |
14 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
15 | Realtime.logger.d { "Subscribed to channel ${message.topic}" }
16 | channel.updateStatus(RealtimeChannel.Status.SUBSCRIBED)
17 | }
18 |
19 | override fun appliesTo(message: RealtimeMessage): Boolean {
20 | return message.event == RealtimeChannel.CHANNEL_EVENT_SYSTEM && message.payload["status"]?.jsonPrimitive?.content == "ok"
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/event/RTokenExpiredEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.event
2 |
3 | import io.github.jan.supabase.logging.w
4 | import io.github.jan.supabase.realtime.Realtime
5 | import io.github.jan.supabase.realtime.RealtimeChannel
6 | import io.github.jan.supabase.realtime.RealtimeMessage
7 | import kotlinx.serialization.json.jsonPrimitive
8 |
9 | /**
10 | * Event that handles the token expired event
11 | */
12 | data object RTokenExpiredEvent : RealtimeEvent {
13 |
14 | override suspend fun handle(channel: RealtimeChannel, message: RealtimeMessage) {
15 | Realtime.logger.w { "Received token expired event. This should not happen, please report this warning." }
16 | }
17 |
18 | override fun appliesTo(message: RealtimeMessage): Boolean {
19 | return message.event == RealtimeChannel.CHANNEL_EVENT_SYSTEM && message.payload["message"]?.jsonPrimitive?.content?.contains("access token has expired") ?: false
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/websocket/KtorRealtimeWebsocketFactory.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.websocket
2 |
3 | import io.ktor.client.HttpClient
4 | import io.ktor.client.plugins.websocket.webSocketSession
5 |
6 | /**
7 | * Implementation of [RealtimeWebsocketFactory] using Ktor's [HttpClient].
8 | */
9 | class KtorRealtimeWebsocketFactory(
10 | private val httpClient: HttpClient,
11 | ): RealtimeWebsocketFactory {
12 |
13 | override suspend fun create(url: String): RealtimeWebsocket {
14 | val ws = httpClient.webSocketSession(url)
15 | return KtorRealtimeWebsocket(ws)
16 | }
17 |
18 | }
--------------------------------------------------------------------------------
/Realtime/src/commonMain/kotlin/io/github/jan/supabase/realtime/websocket/RealtimeWebsocketFactory.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.realtime.websocket
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | /**
6 | * Interface for creating a websocket connection to the Supabase Realtime service.
7 | */
8 | @OptIn(ExperimentalSubclassOptIn::class)
9 | @SubclassOptInRequired(SupabaseInternal::class)
10 | interface RealtimeWebsocketFactory {
11 |
12 | /**
13 | * Create a new websocket connection to the given URL.
14 | * @param url The URL to connect to.
15 | */
16 | suspend fun create(url: String): RealtimeWebsocket
17 |
18 | }
--------------------------------------------------------------------------------
/Realtime/src/commonTest/kotlin/RealtimeTopicTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.realtime.RealtimeTopic
2 | import kotlin.test.Test
3 | import kotlin.test.assertEquals
4 |
5 | class RealtimeTopicTest {
6 |
7 | @Test
8 | fun testRealtimeTopic() {
9 | val channelId = "channelId"
10 | val topic = RealtimeTopic.withChannelId(channelId)
11 | assertEquals("realtime:channelId", topic)
12 | }
13 |
14 | @Test
15 | fun testRealtimePrefix() {
16 | assertEquals("realtime", RealtimeTopic.PREFIX)
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/Storage/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Storage/src/androidMain/kotlin/io/github/jan/supabase/storage/Context.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | private var appContext: Context? = null
7 |
8 | internal class SupabaseInitializer : Initializer {
9 | override fun create(context: Context): Context = context.applicationContext.also { appContext = it }
10 |
11 | override fun dependencies(): List>> = emptyList()
12 |
13 | }
14 |
15 | internal fun applicationContext(): Context = appContext ?: error("Application context not initialized")
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/DownloadOptionBuilder.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import io.github.jan.supabase.network.HttpRequestOverride
4 |
5 | /**
6 | * Builder for downloading files with additional options
7 | */
8 | class DownloadOptionBuilder(
9 | internal var transform: ImageTransformation.() -> Unit = {},
10 | internal val httpRequestOverrides: MutableList = mutableListOf()
11 | ) {
12 |
13 | /**
14 | * Transforms the image before downloading
15 | * @param transform The transformation to apply
16 | */
17 | fun transform(transform: ImageTransformation.() -> Unit) {
18 | this.transform = transform
19 | }
20 |
21 | /**
22 | * Overrides the HTTP request
23 | * @param override The override to apply
24 | */
25 | fun httpOverride(override: HttpRequestOverride) {
26 | httpRequestOverrides.add(override)
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/FileSizeLimit.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import kotlin.jvm.JvmInline
4 |
5 | /**
6 | * A file size limit for buckets
7 | * @param value The value of the limit (e.g. 10mb)
8 | */
9 | @JvmInline
10 | value class FileSizeLimit internal constructor(val value: String)
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/FileUploadResponse.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | /**
4 | * The response of a file upload
5 | * @param id The id of the file
6 | * @param path The path to the file. Can be used as is in [BucketApi] uploading methods
7 | * @param key The key of the file
8 | */
9 | data class FileUploadResponse(
10 | val id: String? = null,
11 | val path: String,
12 | val key: String? = null
13 | )
14 |
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/SignedUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * Represents a signed url
7 | * @param error An optional error message
8 | * @param signedURL The signed url
9 | * @param path The path of the file
10 | */
11 | @Serializable
12 | data class SignedUrl(val error: String? = null, val signedURL: String, val path: String)
13 |
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/StorageErrorResponse.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | internal data class StorageErrorResponse(
7 | val statusCode: Int,
8 | val error: String,
9 | val message: String
10 | )
11 |
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/StorageItem.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | /**
4 | * Represents a file in the storage bucket.
5 | * @param path The path of the file.
6 | * @param bucketId The id of the bucket.
7 | * @param authenticated Whether the file has to be accessed authenticated or not.
8 | */
9 | data class StorageItem(
10 | val path: String,
11 | val bucketId: String,
12 | val authenticated: Boolean
13 | )
14 |
15 | /**
16 | * Creates a [StorageItem] for an authenticated file.
17 | */
18 | fun authenticatedStorageItem(bucketId: String, path: String) = StorageItem(path, bucketId, true)
19 |
20 | /**
21 | * Creates a [StorageItem] for a public file.
22 | */
23 | fun publicStorageItem(bucketId: String, path: String) = StorageItem(path, bucketId, false)
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/UploadData.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import io.ktor.utils.io.ByteReadChannel
4 |
5 | /**
6 | * Represents the data to upload
7 | * @param stream The [ByteReadChannel] for streaming the data
8 | * @param size The size of the data
9 | */
10 | data class UploadData(val stream: ByteReadChannel, val size: Long)
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/UploadSignedUrl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | /**
4 | * A signed url to upload a file
5 | * @param url The signed url
6 | * @param path The path of the file
7 | * @param token The token to use for the upload
8 | */
9 | data class UploadSignedUrl(
10 | val url: String,
11 | val path: String,
12 | val token: String
13 | )
14 |
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage
2 |
3 | import kotlinx.serialization.json.JsonObjectBuilder
4 | import kotlinx.serialization.json.put
5 |
6 | internal fun JsonObjectBuilder.putImageTransformation(transformation: ImageTransformation) {
7 | transformation.width?.let { put("width", it) }
8 | transformation.height?.let { put("height", it) }
9 | transformation.resize?.let { put("resize", it.name.lowercase()) }
10 | transformation.quality?.let { put("quality", it) }
11 | transformation.format?.let { put("format", it) }
12 | }
--------------------------------------------------------------------------------
/Storage/src/commonMain/kotlin/io/github/jan/supabase/storage/resumable/StreamContent.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage.resumable
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 | import io.ktor.http.ContentType
5 | import io.ktor.http.content.OutgoingContent
6 | import io.ktor.utils.io.ByteWriteChannel
7 |
8 | @SupabaseInternal
9 | internal class StreamContent(
10 | size: Long,
11 | private val copyTo: suspend ByteWriteChannel.() -> Unit
12 | ) : OutgoingContent.WriteChannelContent() {
13 |
14 | override val contentLength: Long = size
15 | override val contentType: ContentType = ContentType.parse("application/offset+octet-stream")
16 |
17 | override suspend fun writeTo(channel: ByteWriteChannel) {
18 | copyTo(channel)
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Storage/src/linuxMain/kotlin/io/github/jan/supabase/storage/resumable/ResumableCacheUtil.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.storage.resumable
2 |
3 | import io.github.jan.supabase.annotations.SupabaseInternal
4 |
5 | @SupabaseInternal
6 | actual fun createDefaultResumableCache(): ResumableCache = MemoryResumableCache()
--------------------------------------------------------------------------------
/Supabase/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Supabase/src/androidMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 |
5 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/androidMain/kotlin/io/github/jan/supabase/PlatformTarget.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
4 | name = "Android",
5 | version = android.os.Build.VERSION.RELEASE
6 | )
--------------------------------------------------------------------------------
/Supabase/src/androidMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget = PlatformTarget.ANDROID
--------------------------------------------------------------------------------
/Supabase/src/androidUnitTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.ANDROID, CurrentPlatformTarget, "The current platform target should be ANDROID")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/appleMain/kotlin/io/supabase/supabase/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.supabase.supabase
2 |
3 | import kotlinx.cinterop.ExperimentalForeignApi
4 | import kotlinx.cinterop.UnsafeNumber
5 | import kotlinx.cinterop.useContents
6 |
7 | @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
8 | internal fun getOSVersion(): String {
9 | val processInfo = platform.Foundation.NSProcessInfo.processInfo
10 | return processInfo.operatingSystemVersion.useContents {
11 | val majorVersion = this.majorVersion
12 | val minorVersion = this.minorVersion
13 | val patchVersion = this.patchVersion
14 | buildString {
15 | append(majorVersion)
16 | append(".")
17 | append(minorVersion)
18 | append(".")
19 | append(patchVersion)
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/AccessTokenProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * Optional function for using a third-party authentication system with
5 | * Supabase. The function should return an access token or ID token (JWT) by
6 | * obtaining it from the third-party auth client library. Note that this
7 | * function may be called concurrently and many times. Use memoization and
8 | * locking techniques if this is not supported by the client libraries.
9 | */
10 | typealias AccessTokenProvider = suspend () -> String?
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.CoroutineDispatcher
4 |
5 | internal expect val defaultDispatcher: CoroutineDispatcher
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/SupabaseClientConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.github.jan.supabase.logging.LogLevel
4 | import io.ktor.client.engine.HttpClientEngine
5 | import kotlinx.coroutines.CoroutineDispatcher
6 | import kotlin.time.Duration
7 |
8 | internal data class SupabaseClientConfig(
9 | val supabaseUrl: String,
10 | val supabaseKey: String,
11 | val defaultLogLevel: LogLevel,
12 | val networkConfig: SupabaseNetworkConfig,
13 | val defaultSerializer: SupabaseSerializer,
14 | val coroutineDispatcher: CoroutineDispatcher,
15 | val accessToken: AccessTokenProvider?,
16 | val plugins: Map,
17 | val osInformation: OSInformation?
18 | )
19 |
20 | internal data class SupabaseNetworkConfig(
21 | val useHTTPS: Boolean,
22 | val httpEngine: HttpClientEngine?,
23 | val httpConfigOverrides: List,
24 | val requestTimeout: Duration
25 | )
26 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/annotations/SupabaseDsl.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.annotations
2 |
3 | /**
4 | * Used to mark DSL functions
5 | */
6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE, AnnotationTarget.FUNCTION)
7 | @DslMarker
8 | annotation class SupabaseDsl
9 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/annotations/SupabaseExperimental.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.annotations
2 |
3 | /**
4 | * Used to mark experimental APIs
5 | */
6 | @RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "This API is experimental and may not be stable yet")
7 | annotation class SupabaseExperimental
8 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/annotations/SupabaseInternal.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.annotations
2 |
3 | /**
4 | * Used to mark internal APIs
5 | */
6 | @RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "This API is internal and can change at any time")
7 | annotation class SupabaseInternal
8 |
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/HttpRequestException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.exceptions
2 |
3 | import io.ktor.client.request.HttpRequestBuilder
4 | import kotlinx.io.IOException
5 |
6 | /**
7 | * An exception that is thrown when a request fails due to network issues
8 | */
9 | class HttpRequestException(message: String, request: HttpRequestBuilder): IOException("HTTP request to ${request.url.buildString()} (${request.method.value}) failed with message: $message")
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/exceptions/SupabaseEncodingException.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.exceptions
2 |
3 | /**
4 | * Thrown when an encoding error occurs
5 | */
6 | class SupabaseEncodingException(message: String): Exception(message)
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/logging/LogLevel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.logging
2 |
3 | /**
4 | * Represents a log level
5 | *
6 | */
7 | enum class LogLevel {
8 | /**
9 | * Debug log level
10 | */
11 | DEBUG,
12 |
13 | /**
14 | * Info log level
15 | */
16 | INFO,
17 |
18 | /**
19 | * Warning log level
20 | */
21 | WARNING,
22 | /**
23 | * Error log level
24 | */
25 | ERROR,
26 |
27 | /**
28 | * No log level
29 | */
30 | NONE,
31 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/CustomSerializationConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseClientBuilder
4 | import io.github.jan.supabase.SupabaseSerializer
5 |
6 | /**
7 | * A configuration for a plugin, which allows to customize the serialization
8 | */
9 | interface CustomSerializationConfig {
10 |
11 | /**
12 | * The serializer used for this module. Defaults to [SupabaseClientBuilder.defaultSerializer], when null.
13 | */
14 | var serializer: SupabaseSerializer?
15 |
16 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/CustomSerializationPlugin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseClientBuilder
4 | import io.github.jan.supabase.SupabaseSerializer
5 |
6 | /**
7 | * A plugin, which allows to customize the serialization
8 | */
9 | interface CustomSerializationPlugin {
10 |
11 | /**
12 | * The serializer used for this module. Defaults to [SupabaseClientBuilder.defaultSerializer], when null.
13 | */
14 | val serializer: SupabaseSerializer
15 |
16 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/SerializableData.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseSerializer
4 | import io.github.jan.supabase.annotations.SupabaseInternal
5 |
6 | /**
7 | * An interface for data that can be serialized with [SupabaseSerializer]
8 | */
9 | interface SerializableData {
10 |
11 | /**
12 | * The serializer used to serialize this data
13 | */
14 | @SupabaseInternal
15 | val serializer: SupabaseSerializer
16 |
17 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/plugins/SupabasePlugin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.plugins
2 |
3 | import io.github.jan.supabase.SupabaseClient
4 |
5 | /**
6 | * A plugin is a feature that can be installed into the supabase client
7 | */
8 | interface SupabasePlugin {
9 |
10 | /**
11 | * The config for this plugin
12 | */
13 | val config: Config
14 |
15 | /**
16 | * The corresponding [SupabaseClient]
17 | */
18 | val supabaseClient: SupabaseClient
19 |
20 | /**
21 | * Free all resources used by this plugin
22 | */
23 | suspend fun close() {}
24 |
25 | /**
26 | * Initialize the plugin. Use this function, if you want to execute code after the plugin has been created but also have to access other plugins.
27 | *
28 | * **Note:** This function is called by the [SupabaseClient] after all plugins have been created. Do not call this function manually.
29 | */
30 | fun init() {}
31 |
32 | }
--------------------------------------------------------------------------------
/Supabase/src/commonMain/kotlin/io/github/jan/supabase/serializer/KotlinXSerializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.serializer
2 |
3 | import io.github.jan.supabase.SupabaseSerializer
4 | import kotlinx.serialization.json.Json
5 | import kotlinx.serialization.serializer
6 | import kotlin.reflect.KType
7 |
8 | /**
9 | * A [SupabaseSerializer] that uses kotlinx.serialization
10 | */
11 | class KotlinXSerializer(private val json: Json = Json) : SupabaseSerializer {
12 |
13 | override fun encode(type: KType, value: T): String = json.encodeToString(json.serializersModule.serializer(type), value)
14 |
15 | @Suppress("UNCHECKED_CAST")
16 | override fun decode(type: KType, value: String): T =
17 | json.decodeFromString(json.serializersModule.serializer(type), value) as T
18 |
19 | }
--------------------------------------------------------------------------------
/Supabase/src/commonTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import kotlin.test.Test
2 |
3 | expect class PlatformTargetTest {
4 |
5 | @Test
6 | fun testPlatformTarget()
7 |
8 | }
--------------------------------------------------------------------------------
/Supabase/src/iosMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.IO
5 |
6 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/iosMain/kotlin/io/github/jan/supabase/PlatformTarget.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.supabase.supabase.getOSVersion
4 |
5 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
6 | name = "iOS",
7 | version = getOSVersion()
8 | )
--------------------------------------------------------------------------------
/Supabase/src/iosMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget = PlatformTarget.IOS
--------------------------------------------------------------------------------
/Supabase/src/iosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.IOS, CurrentPlatformTarget, "The current platform target should be IOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/jsMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 |
5 | actual val defaultDispatcher = Dispatchers.Default
--------------------------------------------------------------------------------
/Supabase/src/jsMain/kotlin/io/github/jan/supabase/PlatformTarget.js.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | internal actual fun getOSInformation(): OSInformation? = null
--------------------------------------------------------------------------------
/Supabase/src/jsMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget: PlatformTarget = PlatformTarget.JS
--------------------------------------------------------------------------------
/Supabase/src/jsTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.JS, CurrentPlatformTarget, "The current platform target should be WEB")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/jvmMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 |
5 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/jvmMain/kotlin/io/github/jan/supabase/PlatformTarget.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
4 | name = System.getProperty("os.name"),
5 | version = System.getProperty("os.version")
6 | )
--------------------------------------------------------------------------------
/Supabase/src/jvmMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget = PlatformTarget.JVM
--------------------------------------------------------------------------------
/Supabase/src/jvmTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import io.github.jan.supabase.getOSInformation
4 | import kotlin.test.Test
5 | import kotlin.test.assertEquals
6 |
7 | actual class PlatformTargetTest {
8 |
9 | @Test
10 | actual fun testPlatformTarget() {
11 | assertEquals(PlatformTarget.JVM, CurrentPlatformTarget, "The current platform target should be DESKTOP")
12 | }
13 |
14 | @Test
15 | fun testGetOSInformation() {
16 | System.setProperty("os.name", "Linux")
17 | System.setProperty("os.version", "5.4.0")
18 | val osInfo = getOSInformation()
19 | assertEquals("Linux", osInfo?.name, "OS name should be Linux")
20 | assertEquals("5.4.0", osInfo?.version, "OS version should be 5.4.0")
21 | }
22 |
23 | }
--------------------------------------------------------------------------------
/Supabase/src/linuxMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.IO
5 |
6 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/linuxMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget = PlatformTarget.LINUX
--------------------------------------------------------------------------------
/Supabase/src/linuxMain/kotlin/io/github/jan/supabase/PlatformTarget.linux.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.cinterop.ExperimentalForeignApi
4 | import kotlinx.cinterop.convert
5 | import kotlinx.cinterop.refTo
6 | import platform.posix.fclose
7 | import platform.posix.fopen
8 | import platform.posix.fread
9 |
10 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
11 | name = "Linux",
12 | version = getOSVersion()
13 | )
14 |
15 | private fun getOSVersion(): String = readProcVersion() ?: "Unknown"
16 |
17 | @OptIn(ExperimentalForeignApi::class)
18 | fun readProcVersion(): String? {
19 | val path = "/proc/version"
20 | val file = fopen(path, "r") ?: return null
21 | try {
22 | val buffer = ByteArray(1024)
23 | val bytesRead = fread(buffer.refTo(0), 1.convert(), buffer.size.convert(), file).toInt()
24 | return buffer.decodeToString(endIndex = bytesRead).trim()
25 | } finally {
26 | fclose(file)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Supabase/src/linuxTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.LINUX, CurrentPlatformTarget, "The current platform target should be LINUX")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/macosMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.IO
5 |
6 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/macosMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget = PlatformTarget.MACOS
--------------------------------------------------------------------------------
/Supabase/src/macosMain/kotlin/io/github/jan/supabase/PlatformTarget.macos.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.supabase.supabase.getOSVersion
4 |
5 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
6 | name = "macOS",
7 | version = getOSVersion()
8 | )
--------------------------------------------------------------------------------
/Supabase/src/macosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.MACOS, CurrentPlatformTarget, "The current platform target should be MACOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/mingwMain/kotlin/io/github/jan/supabase/PlatformTarget.mingw.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import platform.windows.DWORD
4 | import platform.windows.GetVersion
5 |
6 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
7 | name = "Windows",
8 | version = getOSVersion()
9 | )
10 |
11 | private fun getOSVersion(): String {
12 | val dwVersion: DWORD = GetVersion()
13 |
14 | val dwMajorVersion = dwVersion and 255u
15 | val dwMinorVersion = (dwVersion shr 8) and 255u
16 | return "$dwMajorVersion.$dwMinorVersion"
17 | }
--------------------------------------------------------------------------------
/Supabase/src/mingwX64Main/kotlin/io/github/jan/supabase/CurrentPlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget: PlatformTarget = PlatformTarget.WINDOWS
--------------------------------------------------------------------------------
/Supabase/src/mingwX64Main/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.IO
5 |
6 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/mingwX64Test/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.WINDOWS, CurrentPlatformTarget, "The current platform target should be WINDOWS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/tvosMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.IO
5 |
6 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/tvosMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget: PlatformTarget = PlatformTarget.TVOS
--------------------------------------------------------------------------------
/Supabase/src/tvosMain/kotlin/io/github/jan/supabase/PlatformTarget.tvos.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.supabase.supabase.getOSVersion
4 |
5 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
6 | name = "tvOS",
7 | version = getOSVersion()
8 | )
--------------------------------------------------------------------------------
/Supabase/src/tvosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.TVOS, CurrentPlatformTarget, "The current platform target should be TVOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/wasmJsMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 |
5 | actual val defaultDispatcher = Dispatchers.Default
--------------------------------------------------------------------------------
/Supabase/src/wasmJsMain/kotlin/io/github/jan/supabase/PlatformTarget.wasmJs.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget: PlatformTarget = PlatformTarget.WASM_JS
7 |
8 | internal actual fun getOSInformation(): OSInformation? = null
--------------------------------------------------------------------------------
/Supabase/src/wasmJsTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.WASM_JS, CurrentPlatformTarget, "The current platform target should be WASM_JS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/Supabase/src/watchosMain/kotlin/io/github/jan/supabase/DefaultDispatcher.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.IO
5 |
6 | actual val defaultDispatcher = Dispatchers.IO
--------------------------------------------------------------------------------
/Supabase/src/watchosMain/kotlin/io/github/jan/supabase/PlatformTarget.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | /**
4 | * The current target platform
5 | */
6 | actual val CurrentPlatformTarget: PlatformTarget = PlatformTarget.WATCHOS
--------------------------------------------------------------------------------
/Supabase/src/watchosMain/kotlin/io/github/jan/supabase/PlatformTarget.watchos.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase
2 |
3 | import io.supabase.supabase.getOSVersion
4 |
5 | internal actual fun getOSInformation(): OSInformation? = OSInformation(
6 | name = "tvOS",
7 | version = getOSVersion()
8 | )
--------------------------------------------------------------------------------
/Supabase/src/watchosTest/kotlin/PlatformTargetTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.CurrentPlatformTarget
2 | import io.github.jan.supabase.PlatformTarget
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | actual class PlatformTargetTest {
7 |
8 | @Test
9 | actual fun testPlatformTarget() {
10 | assertEquals(PlatformTarget.WATCHOS, CurrentPlatformTarget, "The current platform target should be WATCHOS")
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/bom/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `java-platform`
3 | }
4 |
5 | description = "A Kotlin Multiplatform Supabase Framework"
6 |
7 | val bomProject = project
8 |
9 | val excludedModules = listOf("test-common")
10 |
11 | fun shouldIncludeInBom(candidateProject: Project) =
12 | excludedModules.all { !candidateProject.name.contains(it) } &&
13 | candidateProject.name != bomProject.name
14 |
15 | rootProject.subprojects.filter(::shouldIncludeInBom).forEach { bomProject.evaluationDependsOn(it.path) }
16 |
17 | dependencies {
18 | constraints {
19 | rootProject.subprojects.filter { project ->
20 | // Only declare dependencies on projects that will have publications
21 | shouldIncludeInBom(project) && project.tasks.findByName("publish")?.enabled == true
22 | }.forEach { api(project(it.path)) }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | gradlePluginPortal()
7 | mavenCentral()
8 | google()
9 | }
10 |
11 | dependencies {
12 | implementation(libs.kotlin.multiplatform.gradle)
13 | implementation(libs.android.gradle.plugin)
14 | implementation(libs.detekt.gradle)
15 | implementation(libs.dokka.gradle)
16 | implementation(libs.publishing.gradle)
17 | implementation(libs.compose.gradle)
18 | implementation(libs.power.assert.gradle)
19 | }
--------------------------------------------------------------------------------
/buildSrc/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | versionCatalogs {
3 | create("libs") {
4 | from(files("../gradle/libs.versions.toml"))
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/KotlinPlugin.kt:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
2 | import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
3 |
4 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
5 | fun KotlinMultiplatformExtension.defaultConfig() {
6 | sourceSets.all {
7 | languageSettings.optIn("kotlin.RequiresOptIn")
8 | languageSettings.optIn("io.github.jan.supabase.annotations.SupabaseInternal")
9 | languageSettings.optIn("io.github.jan.supabase.annotations.SupabaseExperimental")
10 | }
11 | compilerOptions.freeCompilerArgs.add("-Xexpect-actual-classes")
12 | applyDefaultHierarchyTemplate()
13 | // jvmToolchain(8)
14 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/PowerAssert.kt:
--------------------------------------------------------------------------------
1 | import org.gradle.api.Project
2 | import org.gradle.kotlin.dsl.apply
3 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
4 | import org.jetbrains.kotlin.powerassert.gradle.PowerAssertGradleExtension
5 |
6 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
7 | fun Project.applyPowerAssertConfiguration() {
8 | apply(plugin = "org.jetbrains.kotlin.plugin.power-assert")
9 |
10 | extensions.configure(PowerAssertGradleExtension::class.java) {
11 | functions.addAll(
12 | listOf("kotlin.assert", "kotlin.test.assertTrue", "kotlin.test.assertEquals",
13 | "kotlin.test.assertNull", "kotlin.test.assertIs", "kotlin.test.assertContentContains",
14 | "kotlin.test.assertContains")
15 | )
16 | }
17 | }
--------------------------------------------------------------------------------
/buildSrc/src/main/kotlin/TargetHierarchy.kt:
--------------------------------------------------------------------------------
1 | @file:OptIn(ExperimentalKotlinGradlePluginApi::class)
2 |
3 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
4 | import org.jetbrains.kotlin.gradle.plugin.KotlinHierarchyBuilder
5 |
6 | fun KotlinHierarchyBuilder.androidAndJvmGroup() {
7 | group("androidAndJvm") {
8 | withJvm()
9 | withAndroidTarget()
10 | }
11 | }
12 |
13 | fun KotlinHierarchyBuilder.settingsGroup() {
14 | group("settings") {
15 | withJvm()
16 | withAndroidTarget()
17 | withJs()
18 | withMingwX64()
19 | withApple()
20 | withWasmJs()
21 | }
22 | }
--------------------------------------------------------------------------------
/demos/android-login/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
43 |
44 | local.properties
45 |
46 | /wix311/
--------------------------------------------------------------------------------
/demos/android-login/android/src/main/java/io/github/jan/supabase/android/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.app.Application
4 | import io.github.jan.supabase.common.di.initKoin
5 |
6 | class MainApplication: Application() {
7 |
8 | override fun onCreate() {
9 | super.onCreate()
10 | initKoin()
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/demos/android-login/build.gradle.kts:
--------------------------------------------------------------------------------
1 | group = "io.github.jan.supabase"
2 | version = "1.0-SNAPSHOT"
3 |
4 | plugins {
5 | alias(libs.plugins.kotlin.multiplatform) apply false
6 | alias(libs.plugins.kotlin.android) apply false
7 | alias(libs.plugins.kotlinx.plugin.serialization) apply false
8 | alias(libs.plugins.android.application) apply false
9 | alias(libs.plugins.android.library) apply false
10 | alias(libs.plugins.compose) apply false
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | mavenCentral()
17 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/demos/android-login/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | }
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demos/android-login/buildSrc/src/main/kotlin/Versions.kt:
--------------------------------------------------------------------------------
1 | object Versions {
2 |
3 | const val KOIN = "3.3.3"
4 | const val SUPABASE = "0.8.4"
5 | const val LIFECYCLE = "2.6.0"
6 | const val KTOR = "2.2.4"
7 |
8 | }
--------------------------------------------------------------------------------
/demos/android-login/common/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demos/android-login/common/src/androidMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 |
6 | actual open class MPViewModel actual constructor(): ViewModel() {
7 |
8 | actual val coroutineScope = viewModelScope
9 |
10 | }
--------------------------------------------------------------------------------
/demos/android-login/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.gotrue.GoTrueConfig
4 |
5 | actual fun GoTrueConfig.platformGoTrueConfig() {
6 | scheme = "io.jan.supabase"
7 | host = "login"
8 | }
--------------------------------------------------------------------------------
/demos/android-login/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | viewModel { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/demos/android-login/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/koin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.KoinApplication
4 | import org.koin.core.context.startKoin
5 |
6 | fun initKoin(additionalConfiguration: KoinApplication.() -> Unit = {}) {
7 | startKoin {
8 | modules(supabaseModule, viewModelModule)
9 | additionalConfiguration()
10 | }
11 | }
--------------------------------------------------------------------------------
/demos/android-login/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.AppViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = AppViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/demos/android-login/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | kotlin.native.enableDependencyPropagation=false
3 | android.useAndroidX=true
4 | org.jetbrains.compose.experimental.jscanvas.enabled=true
5 | org.gradle.jvmargs=-Xmx4096m
6 | kotlin.mpp.androidSourceSetLayoutVersion=2
--------------------------------------------------------------------------------
/demos/android-login/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/demos/android-login/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/demos/android-login/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/demos/android-login/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
2 | pluginManagement {
3 | repositories {
4 | google()
5 | gradlePluginPortal()
6 | mavenCentral()
7 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
8 | }
9 | }
10 |
11 | rootProject.name = "android-login"
12 |
13 | include(":android", ":desktop", ":web", ":common")
14 |
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | desktop/output
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### IntelliJ IDEA ###
9 | .idea/modules.xml
10 | .idea/jarRepositories.xml
11 | .idea/compiler.xml
12 | .idea/libraries/
13 | *.iws
14 | *.iml
15 | *.ipr
16 | out/
17 | !**/src/main/**/out/
18 | !**/src/test/**/out/
19 |
20 | ### Eclipse ###
21 | .apt_generated
22 | .classpath
23 | .factorypath
24 | .project
25 | .settings
26 | .springBeans
27 | .sts4-cache
28 | bin/
29 | !**/src/main/**/bin/
30 | !**/src/test/**/bin/
31 |
32 | ### NetBeans ###
33 | /nbproject/private/
34 | /nbbuild/
35 | /dist/
36 | /nbdist/
37 | /.nb-gradle/
38 |
39 | ### VS Code ###
40 | .vscode/
41 |
42 | ### Mac OS ###
43 | .DS_Store
44 |
45 | local.properties
46 |
47 | /wix311/
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/android/src/main/java/io/github/jan/supabase/android/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.material3.MaterialTheme
7 |
8 | import co.touchlab.kermit.Logger
9 | import io.github.jan.supabase.common.App
10 | import io.github.jan.supabase.common.AppViewModel
11 | import io.github.jan.supabase.gotrue.handleDeeplinks
12 | import org.koin.android.ext.android.inject
13 |
14 | class MainActivity : ComponentActivity() {
15 |
16 | private val viewModel: AppViewModel by inject()
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | Logger.base(DebugAntilog())
21 | viewModel.supabaseClient.handleDeeplinks(intent)
22 | setContent {
23 | MaterialTheme {
24 | App(viewModel)
25 | }
26 | }
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/android/src/main/java/io/github/jan/supabase/android/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.app.Application
4 | import io.github.jan.supabase.common.di.initKoin
5 |
6 | class MainApplication: Application() {
7 |
8 | override fun onCreate() {
9 | super.onCreate()
10 | initKoin()
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/build.gradle.kts:
--------------------------------------------------------------------------------
1 | group = "io.github.jan.supabase"
2 | version = "1.0-SNAPSHOT"
3 |
4 | allprojects {
5 | repositories {
6 | google()
7 | mavenCentral()
8 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
9 | mavenLocal()
10 | }
11 | }
12 |
13 | plugins {
14 | alias(libs.plugins.kotlin.multiplatform) apply false
15 | alias(libs.plugins.kotlin.android) apply false
16 | alias(libs.plugins.kotlinx.plugin.serialization) apply false
17 | alias(libs.plugins.android.application) apply false
18 | alias(libs.plugins.android.library) apply false
19 | alias(libs.plugins.compose) apply false
20 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | }
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/buildSrc/src/main/kotlin/Versions.kt:
--------------------------------------------------------------------------------
1 | object Versions {
2 |
3 | const val KOIN = "3.3.3"
4 | const val SUPABASE = "0.8.4"
5 | const val LIFECYCLE = "2.6.0"
6 | const val KTOR = "2.2.4"
7 |
8 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/androidMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 |
6 | actual open class MPViewModel actual constructor(): ViewModel() {
7 |
8 | actual val coroutineScope = viewModelScope
9 |
10 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.gotrue.GoTrueConfig
4 |
5 | actual fun GoTrueConfig.platformGoTrueConfig() {
6 | scheme = "io.github.jan.supabase"
7 | host = "login"
8 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | viewModel { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.material3.Button
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 |
7 | @Composable
8 | actual fun AlertDialog(text: String, close: () -> Unit) {
9 | androidx.compose.material3.AlertDialog(
10 | text = { Text(text) },
11 | onDismissRequest = close,
12 | confirmButton = { Button(onClick = close) { Text("Ok") } }
13 | )
14 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/koin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.KoinApplication
4 | import org.koin.core.context.startKoin
5 |
6 | fun initKoin(additionalConfiguration: KoinApplication.() -> Unit = {}) {
7 | startKoin {
8 | modules(supabaseModule, netModule, viewModelModule)
9 | additionalConfiguration()
10 | }
11 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/netModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.dsl.module
4 |
5 | val netModule = module {
6 |
7 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/supabaseModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.createSupabaseClient
4 | import io.github.jan.supabase.gotrue.GoTrue
5 | import io.github.jan.supabase.gotrue.GoTrueConfig
6 | import org.koin.dsl.module
7 |
8 | expect fun GoTrueConfig.platformGoTrueConfig()
9 |
10 | val supabaseModule = module {
11 | single {
12 | createSupabaseClient(
13 | supabaseUrl = "YOUR_URL",
14 | supabaseKey = "YOUR_KEY"
15 | ) {
16 | install(GoTrue) {
17 | platformGoTrueConfig()
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.AppViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = AppViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | @Composable
6 | expect fun AlertDialog(text: String, close: () -> Unit)
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/screen/AppScreen.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.screen
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.material3.Button
7 | import androidx.compose.material3.Text
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Alignment
10 | import androidx.compose.ui.Modifier
11 | import io.github.jan.supabase.common.AppViewModel
12 |
13 | @Composable
14 | fun AppScreen(viewModel: AppViewModel) {
15 | Column(
16 | modifier = Modifier.fillMaxSize(),
17 | verticalArrangement = Arrangement.Center,
18 | horizontalAlignment = Alignment.CenterHorizontally
19 | ) {
20 | Text("Logged in!")
21 | Button(
22 | onClick = { viewModel.logout() }
23 | ) {
24 | Text("Logout")
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/desktopMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 |
8 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
9 |
10 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.gotrue.GoTrueConfig
4 |
5 | actual fun GoTrueConfig.platformGoTrueConfig() {
6 | htmlTitle = "Chat App"
7 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | kotlin.native.enableDependencyPropagation=false
3 | android.useAndroidX=true
4 | org.jetbrains.compose.experimental.jscanvas.enabled=true
5 | org.gradle.jvmargs=-Xmx4096m
6 | kotlin.mpp.androidSourceSetLayoutVersion=2
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/demos/multiplatform-deeplinks/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
4 | networkTimeout=10000
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/demos/multiplatform-deeplinks/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
2 | pluginManagement {
3 | repositories {
4 | google()
5 | gradlePluginPortal()
6 | mavenCentral()
7 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
8 | maven("https://maven.hq.hydraulic.software")
9 | }
10 | }
11 |
12 | rootProject.name = "multiplatform-deeplinks"
13 |
14 | include(":desktop", ":common", ":android")
15 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx4096m
4 | kotlin.mpp.androidSourceSetLayoutVersion=2
5 | kotlin.native.ignoreDisabledTargets=true
6 | org.gradle.parallel=true
7 | kotlin.suppressGradlePluginWarnings=IncorrectCompileOnlyDependencyWarning
8 |
9 | org.jetbrains.compose.experimental.uikit.enabled=true
10 | org.jetbrains.compose.experimental.jscanvas.enabled=true
11 | org.jetbrains.compose.experimental.wasm.enabled=true
12 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
13 |
14 | supabase-version = 3.2.0-beta-2
15 | base-group = io.github.jan-tennert.supabase
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/plugins/ApolloGraphQL/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugins/Coil3Integration/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Coil3 integration for easy image loading"
7 |
8 | repositories {
9 | mavenCentral()
10 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
11 | }
12 |
13 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
14 | kotlin {
15 | defaultConfig()
16 | composeTargets()
17 | sourceSets {
18 | val commonMain by getting {
19 | dependencies {
20 | api(project(":storage-kt"))
21 | api(libs.bundles.coil3)
22 | }
23 | }
24 | }
25 | }
26 |
27 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/plugins/Coil3Integration/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugins/CoilIntegration/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Coil integration for easy image loading"
7 |
8 | repositories {
9 | mavenCentral()
10 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
11 | }
12 |
13 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
14 | kotlin {
15 | defaultConfig()
16 | configuredAndroidTarget()
17 | sourceSets {
18 | val commonMain by getting {
19 | dependencies {
20 | api(project(":storage-kt"))
21 | api(libs.coil2)
22 | }
23 | }
24 | }
25 | }
26 |
27 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/plugins/CoilIntegration/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/androidMain/kotlin/io/github/jan/supabase/compose/auth/SupabaseInitializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | private var appContext: Context? = null
7 |
8 | internal class SupabaseInitializer : Initializer {
9 | override fun create(context: Context): Context = context.applicationContext.also { appContext = it }
10 |
11 | override fun dependencies(): List>> = emptyList()
12 |
13 | }
14 |
15 | internal fun applicationContext(): Context = appContext ?: error("Application context not initialized")
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/androidMain/kotlin/io/github/jan/supabase/compose/auth/composable/AppleAuth.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.composable
2 |
3 | import androidx.compose.runtime.Composable
4 | import io.github.jan.supabase.compose.auth.ComposeAuth
5 | import io.github.jan.supabase.compose.auth.defaultLoginBehavior
6 |
7 | /**
8 | * Composable function that implements Native Apple Auth.
9 | *
10 | * On unsupported platforms it will use the [fallback]
11 | *
12 | * @param onResult Callback for the result of the login
13 | * @param fallback Fallback function for unsupported platforms
14 | * @return [NativeSignInState]
15 | */
16 | @Composable
17 | actual fun ComposeAuth.rememberSignInWithApple(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit): NativeSignInState = defaultLoginBehavior(fallback)
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/appleMain/kotlin/io/github/jan/supabase/compose/auth/composable/GoogleAuth.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.composable
2 |
3 | import androidx.compose.runtime.Composable
4 | import io.github.jan.supabase.compose.auth.ComposeAuth
5 | import io.github.jan.supabase.compose.auth.defaultLoginBehavior
6 |
7 | /**
8 | * Composable function that implements Native Google Auth.
9 | *
10 | * On unsupported platforms it will use the [fallback]
11 | *
12 | * @param onResult Callback for the result of the login
13 | * @param fallback Fallback function for unsupported platforms
14 | * @return [NativeSignInState]
15 | */
16 | @Composable
17 | actual fun ComposeAuth.rememberSignInWithGoogle(
18 | onResult: (NativeSignInResult) -> Unit,
19 | type: GoogleDialogType,
20 | fallback: suspend () -> Unit
21 | ): NativeSignInState = defaultLoginBehavior(fallback)
22 |
23 | internal actual suspend fun handleGoogleSignOut() = Unit
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/commonMain/kotlin/io/github/jan/supabase/compose/auth/AppleLoginConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth
2 |
3 | /**
4 | * Config for Apple's Authorization API
5 | *
6 | * Note: This is a placeholder for future implementation
7 | */
8 | data object AppleLoginConfig
9 |
10 | /**
11 | * Helper function that return native configs
12 | */
13 | fun ComposeAuth.Config.appleNativeLogin() {
14 | appleLoginConfig = AppleLoginConfig
15 | }
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/commonMain/kotlin/io/github/jan/supabase/compose/auth/Utils.common.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth
2 |
3 | import okio.ByteString.Companion.toByteString
4 |
5 | internal fun String.hash(): String {
6 | val hash = this.encodeToByteArray().toByteString()
7 | return hash.sha256().hex()
8 | }
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/commonMain/kotlin/io/github/jan/supabase/compose/auth/composable/NativeAppleAuth.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.composable
2 |
3 | import androidx.compose.runtime.Composable
4 | import io.github.jan.supabase.auth.providers.Apple
5 | import io.github.jan.supabase.compose.auth.ComposeAuth
6 | import io.github.jan.supabase.compose.auth.fallbackLogin
7 |
8 | /**
9 | * Composable function that implements Native Apple Auth.
10 | *
11 | * On unsupported platforms it will use the [fallback]
12 | *
13 | * @param onResult Callback for the result of the login
14 | * @param fallback Fallback function for unsupported platforms
15 | * @return [NativeSignInState]
16 | */
17 | @Composable
18 | expect fun ComposeAuth.rememberSignInWithApple(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit = { fallbackLogin(Apple) }) : NativeSignInState
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/noDefaultMain/kotlin/io/github/jan/supabase/compose/auth/composable/AppleAuth.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.composable
2 |
3 | import androidx.compose.runtime.Composable
4 | import io.github.jan.supabase.compose.auth.ComposeAuth
5 | import io.github.jan.supabase.compose.auth.defaultLoginBehavior
6 |
7 | /**
8 | * Composable for Apple login with default behavior
9 | */
10 | @Composable
11 | actual fun ComposeAuth.rememberSignInWithApple(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit): NativeSignInState = defaultLoginBehavior(fallback)
--------------------------------------------------------------------------------
/plugins/ComposeAuth/src/noDefaultMain/kotlin/io/github/jan/supabase/compose/auth/composable/GoogleAuth.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.composable
2 |
3 | import androidx.compose.runtime.Composable
4 | import io.github.jan.supabase.compose.auth.ComposeAuth
5 | import io.github.jan.supabase.compose.auth.defaultLoginBehavior
6 |
7 | /**
8 | * Composable function that implements Native Google Auth.
9 | *
10 | * On unsupported platforms it will use the [fallback]
11 | *
12 | * @param onResult Callback for the result of the login
13 | * @param fallback Fallback function for unsupported platforms
14 | * @return [NativeSignInState]
15 | */
16 | @Composable
17 | actual fun ComposeAuth.rememberSignInWithGoogle(
18 | onResult: (NativeSignInResult) -> Unit,
19 | type: GoogleDialogType,
20 | fallback: suspend () -> Unit
21 | ): NativeSignInState = defaultLoginBehavior(fallback)
22 |
23 | internal actual suspend fun handleGoogleSignOut() = Unit
--------------------------------------------------------------------------------
/plugins/ComposeAuthUI/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/plugins/ComposeAuthUI/src/commonMain/kotlin/io/github/jan/supabase/compose/auth/ui/FormValidator.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.ui
2 |
3 | /**
4 | * FormValidator interface used to validate text fields.
5 | */
6 | fun interface FormValidator {
7 |
8 | /**
9 | * Validates the given [value].
10 | */
11 | fun validate(value: String): Boolean
12 |
13 | companion object {
14 |
15 | private val emailRegex = Regex("^[\\w\\-\\.]+@([\\w-]+\\.)+[\\w-]{2,}\$")
16 |
17 | /**
18 | * Validates the given [value] as an email, using REGEX.
19 | */
20 | val EMAIL = FormValidator {
21 | emailRegex.matches(it)
22 | }
23 |
24 | /**
25 | * Validates the given [value] as a phone number, by verifying that all characters are digits.
26 | */
27 | val PHONE = FormValidator {
28 | it.all { char -> char.isDigit() }
29 | }
30 |
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/plugins/ComposeAuthUI/src/commonMain/kotlin/io/github/jan/supabase/compose/auth/ui/annotations/AuthUiExperimental.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.ui.annotations
2 |
3 | /**
4 | * Used to mark experimental Compose Auth Ui APIs
5 | */
6 | @RequiresOptIn(level = RequiresOptIn.Level.ERROR, message = "This API is experimental and may not be stable yet")
7 | annotation class AuthUiExperimental
--------------------------------------------------------------------------------
/plugins/ComposeAuthUI/src/jvmMain/kotlin/io/github/jan/supabase/compose/auth/ui/SvgPainterJvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.compose.auth.ui
2 |
3 | import androidx.compose.ui.graphics.painter.Painter
4 | import androidx.compose.ui.res.loadSvgPainter
5 | import androidx.compose.ui.unit.Density
6 | import io.github.jan.supabase.annotations.SupabaseInternal
7 |
8 | @SupabaseInternal
9 | actual fun svgPainter(bytes: ByteArray, density: Density): Painter = loadSvgPainter(bytes.inputStream(), density)
--------------------------------------------------------------------------------
/plugins/ImageLoaderIntegration/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Compose-ImageLoader integration for easy image loading"
7 |
8 | repositories {
9 | mavenCentral()
10 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
11 | }
12 |
13 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
14 | kotlin {
15 | defaultConfig()
16 | // composeTargets()
17 | jsTarget()
18 | jvmTargets()
19 | iosTargets()
20 | sourceSets {
21 | val commonMain by getting {
22 | dependencies {
23 | api(project(":storage-kt"))
24 | api(libs.imageloader)
25 | implementation(libs.okio)
26 | }
27 | }
28 | }
29 | }
30 |
31 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/plugins/ImageLoaderIntegration/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.compose.plugin.get().pluginId)
3 | alias(libs.plugins.compose.compiler)
4 | id("com.android.application")
5 | id(libs.plugins.kotlin.android.get().pluginId)
6 | alias(libs.plugins.kotlinx.plugin.serialization)
7 | }
8 |
9 | group = "io.github.jan.supabase"
10 | version = "1.0-SNAPSHOT"
11 |
12 | dependencies {
13 | implementation(project(":sample:chat-demo-mpp:common"))
14 | implementation(libs.androidx.activity.compose)
15 | }
16 |
17 | android {
18 | configureApplicationAndroidTarget(JavaVersion.VERSION_11)
19 | kotlinOptions {
20 | jvmTarget = "11"
21 | }
22 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/android/src/main/java/io/github/jan/supabase/android/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.material3.MaterialTheme
7 | import io.github.jan.supabase.auth.handleDeeplinks
8 | import io.github.jan.supabase.common.App
9 | import io.github.jan.supabase.common.ChatViewModel
10 | import org.koin.android.ext.android.inject
11 |
12 | class MainActivity : ComponentActivity() {
13 |
14 | private val viewModel: ChatViewModel by inject()
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | viewModel.supabaseClient.handleDeeplinks(intent)
19 | setContent {
20 | MaterialTheme {
21 | App(viewModel)
22 | }
23 | }
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/android/src/main/java/io/github/jan/supabase/android/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.app.Application
4 | import io.github.jan.supabase.common.di.initKoin
5 |
6 | class MainApplication: Application() {
7 |
8 | override fun onCreate() {
9 | super.onCreate()
10 | initKoin()
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/chatdemoios/chatdemoios.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/androidMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 |
6 | actual open class MPViewModel actual constructor(): ViewModel() {
7 |
8 | actual val coroutineScope = viewModelScope
9 |
10 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 | import io.github.jan.supabase.auth.ExternalAuthAction
5 |
6 | actual fun AuthConfig.platformGoTrueConfig() {
7 | scheme = "io.jan.supabase"
8 | host = "login"
9 | defaultExternalAuthAction = ExternalAuthAction.CustomTabs()
10 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.androidx.viewmodel.dsl.viewModel
4 | import org.koin.core.module.Module
5 |
6 | actual fun Module.viewModel() {
7 | viewModel { createViewModule() }
8 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/koin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.KoinApplication
4 | import org.koin.core.context.startKoin
5 |
6 | fun initKoin(additionalConfiguration: KoinApplication.() -> Unit = {}) {
7 | startKoin {
8 | modules(supabaseModule, netModule, viewModelModule)
9 | additionalConfiguration()
10 | }
11 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/netModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.net.AuthApi
4 | import io.github.jan.supabase.common.net.AuthApiImpl
5 | import io.github.jan.supabase.common.net.MessageApi
6 | import io.github.jan.supabase.common.net.MessageApiImpl
7 | import org.koin.dsl.module
8 |
9 | val netModule = module {
10 | single { MessageApiImpl(get()) }
11 | single { AuthApiImpl(get()) }
12 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.ChatViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = ChatViewModel(get(), get(), get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/desktopMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 |
8 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
9 |
10 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 |
5 | actual fun AuthConfig.platformGoTrueConfig() {
6 | httpCallbackConfig {
7 | this.htmlTitle = "Chat App"
8 | }
9 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/iosMain/kotlin/io/github/jan/supabase/common/App.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.compose.ui.window.ComposeUIViewController
4 | import org.koin.core.component.KoinComponent
5 | import org.koin.core.component.inject
6 | import platform.UIKit.UIViewController
7 |
8 | class RootComponent : KoinComponent {
9 | private val viewModel: ChatViewModel by inject()
10 | fun getViewModel(): ChatViewModel = viewModel
11 | }
12 |
13 | fun AppIos(viewModel: ChatViewModel): UIViewController = ComposeUIViewController {
14 | App(viewModel = viewModel)
15 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/iosMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
8 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/iosMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 |
5 | actual fun AuthConfig.platformGoTrueConfig() {
6 | scheme = "io.jan.supabase"
7 | host = "login"
8 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/iosMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/jsMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 |
8 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
9 |
10 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/jsMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 |
5 | actual fun AuthConfig.platformGoTrueConfig() = Unit
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/common/src/jsMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/desktop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
5 | id(libs.plugins.compose.plugin.get().pluginId)
6 | alias(libs.plugins.compose.compiler)
7 | alias(libs.plugins.kotlinx.plugin.serialization)
8 | }
9 |
10 | group = "io.github.jan.supabase"
11 | version = "1.0-SNAPSHOT"
12 |
13 |
14 | kotlin {
15 | jvmToolchain(11)
16 | jvm {
17 | compilerOptions {
18 | jvmTarget = JvmTarget.JVM_11
19 | }
20 | }
21 | sourceSets {
22 | val jvmMain by getting {
23 | dependencies {
24 | implementation(project(":sample:chat-demo-mpp:common"))
25 | implementation(compose.desktop.currentOs)
26 | }
27 | }
28 | val jvmTest by getting
29 | }
30 | }
31 |
32 | compose.desktop.configureComposeDesktop("chat-demo-mpp")
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/desktop/src/jvmMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.Window
2 | import androidx.compose.ui.window.application
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.ChatViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | class RootComponent : KoinComponent {
10 |
11 | val viewModel: ChatViewModel by inject()
12 |
13 | }
14 |
15 | fun main() {
16 | initKoin()
17 | val root = RootComponent()
18 | application {
19 | Window(onCloseRequest = ::exitApplication, title = "Chat App") {
20 | App(root.viewModel)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/xcuserdata/hieuvu.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/xcuserdata/hieuvu.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/project.xcworkspace/xcuserdata/hieuvu.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | ShowSharedSchemesAutomaticallyEnabled
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcodeproj/xcuserdata/hieuvu.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | chatdemoios.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 2
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 6581F14D2B36C0CF00BA34A9
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios.xcworkspace/xcuserdata/hieuvu.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/supabase-community/supabase-kt/8d9207594a4f651f3f8ff2e4a5082787d7f15deb/sample/chat-demo-mpp/ios/chatdemoios.xcworkspace/xcuserdata/hieuvu.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // chatdemoios
4 | //
5 | // Created by Hieu Vu on 23/12/2023.
6 | //
7 |
8 | import SwiftUI
9 | import common
10 |
11 |
12 | struct ContentView: UIViewControllerRepresentable {
13 |
14 | let viewModel: ChatViewModel = RootComponent().getViewModel()
15 |
16 | func makeUIViewController(context: Context) -> UIViewController {
17 | return AppKt.AppIos(viewModel: viewModel)
18 | }
19 |
20 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/chatdemoios.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/ios/chatdemoios/chatdemoiosApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // chatdemoiosApp.swift
3 | // chatdemoios
4 | //
5 | // Created by Hieu Vu on 23/12/2023.
6 | //
7 |
8 | import SwiftUI
9 | import common
10 |
11 | @main
12 | struct chatdemoiosApp: App {
13 |
14 | init() {
15 | KoinKt.doInitKoin(additionalConfiguration: {_ in})
16 | }
17 |
18 | var body: some Scene {
19 | WindowGroup {
20 | ContentView()
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.compose.plugin.get().pluginId)
4 | alias(libs.plugins.compose.compiler)
5 | alias(libs.plugins.kotlinx.plugin.serialization)
6 | }
7 |
8 | group = "io.github.jan.supabase"
9 | version = "1.0-SNAPSHOT"
10 |
11 |
12 | kotlin {
13 | js(IR) {
14 | browser()
15 | binaries.executable()
16 | }
17 | sourceSets {
18 | val jsMain by getting {
19 | dependencies {
20 | implementation(project(":sample:chat-demo-mpp:common"))
21 | }
22 | }
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/src/jsMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 | import androidx.compose.ui.ExperimentalComposeUiApi
3 | import androidx.compose.ui.window.CanvasBasedWindow
4 | import io.github.jan.supabase.common.App
5 | import io.github.jan.supabase.common.ChatViewModel
6 | import io.github.jan.supabase.common.di.initKoin
7 | import org.jetbrains.skiko.wasm.onWasmReady
8 | import org.koin.core.component.KoinComponent
9 | import org.koin.core.component.inject
10 |
11 | class RootComponent : KoinComponent {
12 |
13 | val viewModel: ChatViewModel by inject()
14 |
15 | }
16 |
17 | @OptIn(ExperimentalComposeUiApi::class)
18 | fun main() {
19 | initKoin()
20 | val root = RootComponent()
21 | onWasmReady {
22 | CanvasBasedWindow(title = "Demo Chat App") {
23 | App(root.viewModel)
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/src/jsMain/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Chat App
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/chat-demo-mpp/web/src/jsMain/resources/styles.css:
--------------------------------------------------------------------------------
1 | #root {
2 | width: 100%;
3 | height: 100vh;
4 | }
5 |
6 | #root > .compose-web-column > div {
7 | position: relative;
8 | }
9 |
10 | canvas {
11 | padding: 0;
12 | margin: auto;
13 | display: block;
14 | width: 800px;
15 | }
--------------------------------------------------------------------------------
/sample/file-upload/README.md:
--------------------------------------------------------------------------------
1 | # File Upload Demo
2 |
3 | This is a demo of a file upload application using Compose Multiplatform, Koin and supabase-kt.
4 |
5 | **Available platforms:** Android, Desktop
6 |
7 | **Modules used:** Storage
8 |
9 | https://user-images.githubusercontent.com/26686035/233403165-26d87217-a0c9-4abd-b677-c367a5f1e4b9.mp4
10 |
11 | # Configuration
12 |
13 | To run the app, you need to create a Supabase project and create a public bucket with the permissions for anonymous users to upload files.
14 |
15 | Then you need to specify your bucket id, Supabase url and key in [supabaseModule.kt](https://github.com/supabase-community/supabase-kt/blob/master/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/supabaseModule.kt)
16 |
17 | # Running
18 |
19 | To run the app, you need to run the following command in the root directory of the project:
20 |
21 | ./gradlew :sample:file-upload:desktop:runDistributable (Desktop)
22 |
23 | For android, use the IDE to run the app.
24 |
--------------------------------------------------------------------------------
/sample/file-upload/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.compose.plugin.get().pluginId)
3 | alias(libs.plugins.compose.compiler)
4 | id("com.android.application")
5 | id(libs.plugins.kotlin.android.get().pluginId)
6 | alias(libs.plugins.kotlinx.plugin.serialization)
7 | }
8 |
9 | group = "io.github.jan.supabase"
10 | version = "1.0-SNAPSHOT"
11 |
12 | dependencies {
13 | implementation(project(":sample:file-upload:common"))
14 | implementation(libs.androidx.activity.compose)
15 | implementation(libs.accompanist.permissions)
16 | }
17 |
18 | android {
19 | configureApplicationAndroidTarget(JavaVersion.VERSION_11)
20 | kotlinOptions {
21 | jvmTarget = "11"
22 | }
23 | }
--------------------------------------------------------------------------------
/sample/file-upload/android/src/main/java/io/github/jan/supabase/android/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.app.Application
4 | import io.github.jan.supabase.common.di.initKoin
5 |
6 | class MainApplication: Application() {
7 |
8 | override fun onCreate() {
9 | super.onCreate()
10 | initKoin()
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 |
6 | actual open class MPViewModel actual constructor(): ViewModel() {
7 |
8 | actual val coroutineScope = viewModelScope
9 |
10 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/SupabaseInitializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 |
6 | private var appContext: Context? = null
7 |
8 | internal class SupabaseInitializer : Initializer {
9 | override fun create(context: Context): Context = context.applicationContext.also { appContext = it }
10 |
11 | override fun dependencies(): List>> = emptyList()
12 |
13 | }
14 |
15 | internal fun applicationContext(): Context = appContext ?: error("Application context not initialized")
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.androidx.viewmodel.dsl.viewModel
4 | import org.koin.core.module.Module
5 |
6 | actual fun Module.viewModel() {
7 | viewModel { createViewModule() }
8 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/parseFileTreeFromPath.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import io.github.jan.supabase.storage.resumable.ResumableClient
4 | import io.github.jan.supabase.storage.resumable.ResumableUpload
5 | import io.github.vinceglb.filekit.core.PlatformFile
6 | import kotlinx.coroutines.Deferred
7 |
8 | actual fun parseFileTreeFromPath(path: String): List {
9 | TODO("Not yet implemented")
10 | }
11 |
12 | actual fun parseFileTreeFromURIs(paths: List): List {
13 | TODO("Not yet implemented")
14 | }
15 |
16 | actual suspend fun ResumableClient.continuePreviousPlatformUploads(): List> = throw UnsupportedOperationException()
17 | //not supported as you loose access to the uri's file after the app is closed
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.material3.Button
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 |
7 | @Composable
8 | actual fun AlertDialog(text: String, close: () -> Unit) {
9 | androidx.compose.material3.AlertDialog(
10 | text = { Text(text) },
11 | onDismissRequest = close,
12 | confirmButton = { Button(onClick = close) { Text("Ok") } }
13 | )
14 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/utils/applyDragging.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | import androidx.compose.runtime.MutableState
4 | import androidx.compose.ui.Modifier
5 |
6 | actual fun Modifier.applyDragging(isDragging: MutableState, onSuccess: (List) -> Unit): Modifier = this
--------------------------------------------------------------------------------
/sample/file-upload/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/utils/bytesToBitmap.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | import android.graphics.BitmapFactory
4 | import androidx.compose.ui.graphics.ImageBitmap
5 | import androidx.compose.ui.graphics.asImageBitmap
6 |
7 | actual fun bytesToBitmap(bytes: ByteArray): ImageBitmap = BitmapFactory.decodeByteArray (bytes, 0, bytes.size).asImageBitmap()
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/App.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.compose.runtime.Composable
4 | import io.github.jan.supabase.common.ui.screen.UploadScreen
5 |
6 | @Composable
7 | fun App(viewModel: UploadViewModel) {
8 | UploadScreen(viewModel)
9 | }
10 |
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/Uploads.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import io.github.jan.supabase.storage.resumable.Fingerprint
4 | import io.github.jan.supabase.storage.resumable.ResumableUploadState
5 | import io.github.vinceglb.filekit.core.PlatformFile
6 | import io.ktor.utils.io.ByteReadChannel
7 |
8 | sealed interface UploadState {
9 |
10 | val fingerprint: Fingerprint
11 |
12 | data class Loading(override val fingerprint: Fingerprint) : UploadState
13 | data class Loaded(override val fingerprint: Fingerprint, val state: ResumableUploadState) : UploadState
14 |
15 | }
16 |
17 | expect val PlatformFile.dataProducer: suspend (offset: Long) -> ByteReadChannel
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/Utils.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.compose.ui.ExperimentalComposeUiApi
4 | import io.github.jan.supabase.storage.resumable.ResumableClient
5 | import io.github.jan.supabase.storage.resumable.ResumableUpload
6 | import io.github.vinceglb.filekit.core.PlatformFile
7 | import kotlinx.coroutines.Deferred
8 |
9 | @OptIn(ExperimentalComposeUiApi::class)
10 | expect fun parseFileTreeFromURIs(paths: List): List
11 |
12 | expect fun parseFileTreeFromPath(path: String): List
13 |
14 | expect suspend fun ResumableClient.continuePreviousPlatformUploads(): List>
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/koin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.KoinApplication
4 | import org.koin.core.context.startKoin
5 |
6 | fun initKoin(additionalConfiguration: KoinApplication.() -> Unit = {}) {
7 | startKoin {
8 | modules(supabaseModule, viewModelModule)
9 | additionalConfiguration()
10 | }
11 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.UploadViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = UploadViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | @Composable
6 | expect fun AlertDialog(text: String, close: () -> Unit)
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/utils/Bitmap.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | import androidx.compose.ui.graphics.ImageBitmap
4 |
5 | expect fun bytesToBitmap(bytes: ByteArray): ImageBitmap
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/utils/Dragging.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | import androidx.compose.runtime.MutableState
4 | import androidx.compose.ui.Modifier
5 |
6 | expect fun Modifier.applyDragging(isDragging: MutableState, onSuccess: (List) -> Unit): Modifier
--------------------------------------------------------------------------------
/sample/file-upload/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/utils/FileSize.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | val Long.fileSize: String
4 | get() {
5 | val size = this.toDouble()
6 | return when {
7 | size < 1024 -> "${size.toLong()} B"
8 | size < 1024 * 1024 -> "${(size / 1024).toLong()} KB"
9 | size < 1024 * 1024 * 1024 -> "${(size / 1024 / 1024).toLong()} MB"
10 | else -> "${(size / 1024 / 1024 / 1024).toLong()} GB"
11 | }
12 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/desktopMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 |
8 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
9 |
10 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/desktopMain/kotlin/io/github/jan/supabase/common/Uploads.desktop.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import io.github.vinceglb.filekit.core.PlatformFile
4 | import io.ktor.util.cio.readChannel
5 | import io.ktor.utils.io.ByteReadChannel
6 |
7 | actual val PlatformFile.dataProducer: suspend (offset: Long) -> ByteReadChannel get() = { offset ->
8 | this.file.readChannel(start = offset)
9 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/sample/file-upload/common/src/desktopMain/kotlin/io/github/jan/supabase/common/ui/utils/bytesToBitmap.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.utils
2 |
3 | import androidx.compose.ui.graphics.ImageBitmap
4 | import androidx.compose.ui.graphics.toComposeImageBitmap
5 |
6 | actual fun bytesToBitmap(bytes: ByteArray): ImageBitmap = org.jetbrains.skia.Image.makeFromEncoded(bytes).toComposeImageBitmap()
--------------------------------------------------------------------------------
/sample/file-upload/desktop/src/jvmMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.Window
2 | import androidx.compose.ui.window.application
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.UploadViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | class RootComponent : KoinComponent {
10 |
11 | val viewModel: UploadViewModel by inject()
12 |
13 | }
14 |
15 | fun main() {
16 | initKoin()
17 | val root = RootComponent()
18 | application {
19 | Window(onCloseRequest = ::exitApplication, title = "File Upload") {
20 | App(root.viewModel)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/android/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.compose.plugin.get().pluginId)
3 | alias(libs.plugins.compose.compiler)
4 | id("com.android.application")
5 | id(libs.plugins.kotlin.android.get().pluginId)
6 | alias(libs.plugins.kotlinx.plugin.serialization)
7 | }
8 |
9 | group = "io.github.jan.supabase"
10 | version = "1.0-SNAPSHOT"
11 |
12 | dependencies {
13 | implementation(libs.androidx.activity.compose)
14 | implementation(project(":sample:multi-factor-auth:common"))
15 | }
16 |
17 | android {
18 | configureApplicationAndroidTarget(JavaVersion.VERSION_11)
19 | kotlinOptions {
20 | jvmTarget = "11"
21 | }
22 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/android/src/main/java/io/github/jan/supabase/android/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.material3.MaterialTheme
7 | import io.github.jan.supabase.auth.handleDeeplinks
8 | import io.github.jan.supabase.common.App
9 | import io.github.jan.supabase.common.AppViewModel
10 | import org.koin.android.ext.android.inject
11 |
12 | class MainActivity : ComponentActivity() {
13 |
14 | private val viewModel: AppViewModel by inject()
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | viewModel.supabaseClient.handleDeeplinks(intent)
19 | setContent {
20 | MaterialTheme {
21 | App(viewModel)
22 | }
23 | }
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/android/src/main/java/io/github/jan/supabase/android/MainApplication.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.android
2 |
3 | import android.app.Application
4 | import io.github.jan.supabase.common.di.initKoin
5 |
6 | class MainApplication: Application() {
7 |
8 | override fun onCreate() {
9 | super.onCreate()
10 | initKoin()
11 | }
12 |
13 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 |
6 | actual open class MPViewModel actual constructor(): ViewModel() {
7 |
8 | actual val coroutineScope = viewModelScope
9 |
10 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 |
5 | actual fun AuthConfig.platformGoTrueConfig() {
6 | scheme = "io.jan.supabase"
7 | host = "login"
8 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.androidx.viewmodel.dsl.viewModel
4 | import org.koin.core.module.Module
5 |
6 | actual fun Module.viewModel() {
7 | viewModel { createViewModule() }
8 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.material3.Button
4 | import androidx.compose.material3.Text
5 | import androidx.compose.runtime.Composable
6 |
7 | @Composable
8 | actual fun AlertDialog(text: String, close: () -> Unit) {
9 | androidx.compose.material3.AlertDialog(
10 | text = { Text(text) },
11 | onDismissRequest = close,
12 | confirmButton = { Button(onClick = close) { Text("Ok") } }
13 | )
14 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/androidMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.remember
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.platform.LocalContext
7 | import coil.ImageLoader
8 | import coil.compose.AsyncImage
9 | import coil.decode.SvgDecoder
10 | import java.nio.ByteBuffer
11 |
12 | @Composable
13 | actual fun QRCode(svgData: String, modifier: Modifier) {
14 | val context = LocalContext.current
15 | val imageLoader = remember {
16 | ImageLoader.Builder(context)
17 | .components {
18 | add(SvgDecoder.Factory())
19 | }
20 | .build()
21 | }
22 | AsyncImage(model = ByteBuffer.wrap(svgData.toByteArray()), imageLoader = imageLoader, modifier = modifier, contentDescription = null)
23 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/koin.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.KoinApplication
4 | import org.koin.core.context.startKoin
5 |
6 | fun initKoin(additionalConfiguration: KoinApplication.() -> Unit = {}) {
7 | startKoin {
8 | modules(supabaseModule, netModule, viewModelModule)
9 | additionalConfiguration()
10 | }
11 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/netModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.dsl.module
4 |
5 | val netModule = module {
6 |
7 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/supabaseModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.Auth
4 | import io.github.jan.supabase.auth.AuthConfig
5 | import io.github.jan.supabase.createSupabaseClient
6 | import org.koin.dsl.module
7 |
8 | expect fun AuthConfig.platformGoTrueConfig()
9 |
10 | val supabaseModule = module {
11 | single {
12 | createSupabaseClient(
13 | supabaseUrl = "YOUR_URL",
14 | supabaseKey = "YOUR_KEY"
15 | ) {
16 | install(Auth) {
17 | platformGoTrueConfig()
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/di/viewModelModule.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.common.AppViewModel
4 | import org.koin.core.module.Module
5 | import org.koin.core.scope.Scope
6 | import org.koin.dsl.module
7 |
8 | expect fun Module.viewModel()
9 |
10 | fun Scope.createViewModule() = AppViewModel(get())
11 |
12 | val viewModelModule = module {
13 | viewModel()
14 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | @Composable
6 | expect fun AlertDialog(text: String, close: () -> Unit)
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.Modifier
5 |
6 | @Composable
7 | expect fun QRCode(
8 | svgData: String,
9 | modifier: Modifier = Modifier,
10 | )
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/commonMain/kotlin/io/github/jan/supabase/common/ui/screen/MfaScreen.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.screen
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.collectAsState
5 | import androidx.compose.runtime.getValue
6 | import io.github.jan.supabase.auth.mfa.MfaStatus
7 | import io.github.jan.supabase.common.AppViewModel
8 |
9 | @Composable
10 | fun MfaScreen(viewModel: AppViewModel) {
11 | val status by viewModel.statusFlow.collectAsState(MfaStatus(false, false))
12 | when {
13 | status.enabled && status.active -> { //only when logged in using mfa & mfa enabled
14 | AppScreen(viewModel)
15 | }
16 | status.enabled && !status.active -> { //show only when mfa enabled & not logged in using mfa
17 | MfaLoginScreen(viewModel)
18 | }
19 | else -> { //show only when logged in using mfa and mfa disabled or not set up
20 | MfaSetupScreen(viewModel)
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/desktopMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 |
8 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
9 |
10 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 |
5 | actual fun AuthConfig.platformGoTrueConfig() {
6 | httpCallbackConfig { htmlTitle = "Chat App" }
7 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/desktopMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/desktopMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.res.loadSvgPainter
8 | import androidx.compose.ui.unit.Density
9 |
10 | @Composable
11 | actual fun QRCode(svgData: String, modifier: Modifier) {
12 | val painter = remember { loadSvgPainter(svgData.byteInputStream(), Density(1f)) }
13 | Image(painter, null, modifier)
14 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/jsMain/kotlin/io/github/jan/supabase/common/MPViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.Dispatchers
5 |
6 | actual open class MPViewModel actual constructor() {
7 |
8 | actual val coroutineScope = CoroutineScope(Dispatchers.Default)
9 |
10 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/jsMain/kotlin/io/github/jan/supabase/common/di/platformGoTrueConfig.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import io.github.jan.supabase.auth.AuthConfig
4 |
5 | actual fun AuthConfig.platformGoTrueConfig() {
6 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/jsMain/kotlin/io/github/jan/supabase/common/di/viewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | actual fun Module.viewModel() {
6 | single { createViewModule() }
7 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/jsMain/kotlin/io/github/jan/supabase/common/ui/components/AlertDialog.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.runtime.Composable
4 | import kotlinx.browser.window
5 |
6 | @Composable
7 | actual fun AlertDialog(text: String, close: () -> Unit) {
8 | window.alert(text)
9 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/common/src/jsMain/kotlin/io/github/jan/supabase/common/ui/components/QRCode.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.common.ui.components
2 |
3 | import androidx.compose.foundation.Canvas
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
8 | import androidx.compose.ui.graphics.nativeCanvas
9 | import org.jetbrains.skia.Data
10 | import org.jetbrains.skia.svg.SVGDOM
11 |
12 | @Composable
13 | actual fun QRCode(svgData: String, modifier: Modifier) {
14 | val svgDom = remember { SVGDOM(data = Data.makeFromBytes(svgData.encodeToByteArray())) }
15 | Canvas(modifier = modifier) {
16 | svgDom.setContainerSize(size.width,size.height)
17 | drawIntoCanvas { canvas ->
18 | svgDom.render(canvas.nativeCanvas)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/desktop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2 |
3 | plugins {
4 | id(libs.plugins.compose.plugin.get().pluginId)
5 | alias(libs.plugins.compose.compiler)
6 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
7 | alias(libs.plugins.kotlinx.plugin.serialization)
8 | }
9 |
10 | group = "io.github.jan.supabase"
11 | version = "1.0-SNAPSHOT"
12 |
13 |
14 | kotlin {
15 | jvmToolchain(11)
16 | jvm {
17 | compilerOptions {
18 | jvmTarget = JvmTarget.JVM_11
19 | }
20 | }
21 | sourceSets {
22 | val jvmMain by getting {
23 | dependencies {
24 | implementation(project(":sample:multi-factor-auth:common"))
25 | implementation(compose.desktop.currentOs)
26 | }
27 | }
28 | val jvmTest by getting
29 | }
30 | }
31 |
32 | compose.desktop.configureComposeDesktop("multi-factor-auth")
--------------------------------------------------------------------------------
/sample/multi-factor-auth/desktop/src/jvmMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.Window
2 | import androidx.compose.ui.window.application
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.AppViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.koin.core.component.KoinComponent
7 | import org.koin.core.component.inject
8 |
9 | class RootComponent : KoinComponent {
10 |
11 | val viewModel: AppViewModel by inject()
12 |
13 | }
14 |
15 | fun main() {
16 | initKoin()
17 | val root = RootComponent()
18 | application {
19 | Window(onCloseRequest = ::exitApplication, title = "MFA App") {
20 | App(root.viewModel)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/web/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.compose.plugin.get().pluginId)
3 | alias(libs.plugins.compose.compiler)
4 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
5 | alias(libs.plugins.kotlinx.plugin.serialization)
6 | }
7 |
8 | group = "io.github.jan.supabase"
9 | version = "1.0-SNAPSHOT"
10 |
11 |
12 | kotlin {
13 | applyDefaultHierarchyTemplate()
14 | js(IR) {
15 | browser()
16 | binaries.executable()
17 | }
18 | sourceSets {
19 | val jsMain by getting {
20 | dependencies {
21 | implementation(project(":sample:multi-factor-auth:common"))
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/web/src/jsMain/kotlin/Main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.ExperimentalComposeUiApi
2 | import androidx.compose.ui.window.CanvasBasedWindow
3 | import io.github.jan.supabase.common.App
4 | import io.github.jan.supabase.common.AppViewModel
5 | import io.github.jan.supabase.common.di.initKoin
6 | import org.jetbrains.skiko.wasm.onWasmReady
7 | import org.koin.core.component.KoinComponent
8 | import org.koin.core.component.inject
9 |
10 | class RootComponent : KoinComponent {
11 |
12 | val viewModel: AppViewModel by inject()
13 |
14 | }
15 |
16 | @OptIn(ExperimentalComposeUiApi::class)
17 | fun main() {
18 | initKoin()
19 | val root = RootComponent()
20 | onWasmReady {
21 | CanvasBasedWindow(title = "MFA App") {
22 | App(root.viewModel)
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/sample/multi-factor-auth/web/src/jsMain/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Chat App
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/multi-factor-auth/web/src/jsMain/resources/styles.css:
--------------------------------------------------------------------------------
1 | #root {
2 | width: 100%;
3 | height: 100vh;
4 | }
5 |
6 | #root > .compose-web-column > div {
7 | position: relative;
8 | }
9 |
10 | canvas {
11 | padding: 0;
12 | margin: auto;
13 | display: block;
14 | width: 800px;
15 | }
--------------------------------------------------------------------------------
/serializers/Jackson/README.md:
--------------------------------------------------------------------------------
1 | # Jackson Serializer
2 |
3 | # Installation
4 |
5 | ### Add the module to your project
6 |
7 | ```kotlin
8 | dependencies {
9 | implementation("io.github.jan-tennert.supabase:serializer-jackson:VERSION")
10 | }
11 | ```
--------------------------------------------------------------------------------
/serializers/Jackson/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id(libs.plugins.kotlin.multiplatform.get().pluginId)
3 | id(libs.plugins.android.library.get().pluginId)
4 | }
5 |
6 | description = "Extends supabase-kt with a Jackson Serializer"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | defaultConfig()
15 | configuredAndroidTarget()
16 | configuredJvmTarget()
17 | sourceSets {
18 | val commonMain by getting {
19 | dependencies {
20 | addModules(SupabaseModule.SUPABASE)
21 | api(libs.bundles.jackson)
22 | }
23 | }
24 | val commonTest by getting {
25 | dependencies {
26 | implementation(libs.bundles.testing)
27 | implementation(project(":test-common"))
28 | }
29 | }
30 | }
31 | }
32 |
33 | configureLibraryAndroidTarget()
--------------------------------------------------------------------------------
/serializers/Jackson/src/commonMain/kotlin/io/github/jan/supabase/serializer/JacksonSerializer.kt:
--------------------------------------------------------------------------------
1 | package io.github.jan.supabase.serializer
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper
4 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
5 | import io.github.jan.supabase.SupabaseSerializer
6 | import kotlin.reflect.KType
7 | import kotlin.reflect.javaType
8 |
9 | /**
10 | * A [SupabaseSerializer] that uses jackson-module-kotlin
11 | */
12 | class JacksonSerializer(private val mapper: ObjectMapper = jacksonObjectMapper()) : SupabaseSerializer {
13 |
14 | override fun encode(type: KType, value: T): String = mapper.writeValueAsString(value)
15 |
16 | @OptIn(ExperimentalStdlibApi::class)
17 | override fun decode(type: KType, value: String): T = mapper.readValue(value, mapper.constructType(type.javaType))
18 |
19 | }
--------------------------------------------------------------------------------
/serializers/Jackson/src/commonTest/kotlin/JacksonSerializerTest.kt:
--------------------------------------------------------------------------------
1 | import io.github.jan.supabase.encode
2 | import io.github.jan.supabase.serializer.JacksonSerializer
3 | import io.github.jan.supabase.testing.createMockedSupabaseClient
4 | import kotlin.reflect.typeOf
5 | import kotlin.test.Test
6 | import kotlin.test.assertEquals
7 |
8 | class JacksonSerializerTest {
9 |
10 | @Test
11 | fun testJacksonSerializer() {
12 | val serializer = JacksonSerializer()
13 | val supabaseClient = createMockedSupabaseClient(
14 | configuration = {
15 | defaultSerializer = serializer
16 | }
17 | )
18 | assertEquals(serializer,supabaseClient.defaultSerializer)
19 | val value = mapOf("key" to "value")
20 | val encoded = serializer.encode(value)
21 | val decoded = serializer.decode