Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[*.{kt,kts}]
ktlint_code_style = ktlint_official
ktlint_standard_property-naming = disabled
79 changes: 39 additions & 40 deletions PowerSync/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import co.touchlab.faktory.artifactmanager.ArtifactManager
import co.touchlab.faktory.capitalized
import co.touchlab.skie.configuration.SuspendInterop
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import java.net.URL
import java.security.MessageDigest
Expand All @@ -10,14 +9,15 @@ plugins {
alias(libs.plugins.kmmbridge)
alias(libs.plugins.skie)
alias(libs.plugins.mavenPublishPlugin)
alias(libs.plugins.kotlinter)
id("com.powersync.plugins.sonatype")
}

kotlin {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
iosSimulatorArm64(),
).forEach {
it.binaries.framework {
export(project(":core"))
Expand All @@ -40,16 +40,6 @@ kotlin {
}
}

skie {
features {
group {
// We turn this off as the suspend interop feature results in
// threading issues when implementing SDK in Swift
SuspendInterop.Enabled(false)
}
}
}

kmmbridge {
artifactManager.set(SonatypePortalPublishArtifactManager(project, repositoryName = null))
artifactManager.finalizeValue()
Expand All @@ -70,19 +60,22 @@ class SonatypePortalPublishArtifactManager(
val project: Project,
private val publicationName: String = "KMMBridgeFramework",
artifactSuffix: String = "kmmbridge",
private val repositoryName: String?,
private val repositoryName: String?
) : ArtifactManager {
private val group: String = project.group.toString().replace(".", "/")
private val kmmbridgeArtifactId =
"${project.name}-${artifactSuffix}"
"${project.name}-$artifactSuffix"
private val LIBRARY_VERSION: String by project

// This is the URL that will be added to Package.swift in Github package so that
// KMMBridge is downloaded when a user includes the package in XCode
private val MAVEN_CENTRAL_PACKAGE_ZIP_URL = "https://repo1.maven.org/maven2/com/powersync/${kmmbridgeArtifactId.lowercase()}/${LIBRARY_VERSION}/${kmmbridgeArtifactId.lowercase()}-${LIBRARY_VERSION}.zip"

override fun deployArtifact(project: Project, zipFilePath: File, version: String): String {
return MAVEN_CENTRAL_PACKAGE_ZIP_URL
}
override fun deployArtifact(
project: Project,
zipFilePath: File,
version: String
): String = MAVEN_CENTRAL_PACKAGE_ZIP_URL

override fun configure(
project: Project,
Expand All @@ -91,12 +84,14 @@ class SonatypePortalPublishArtifactManager(
kmmPublishTask: TaskProvider<Task>
) {
project.extensions.getByType<PublishingExtension>().publications.create(
publicationName, MavenPublication::class.java
publicationName,
MavenPublication::class.java,
) {
this.version = version
val archiveProvider = project.tasks.named("zipXCFramework", Zip::class.java).flatMap {
it.archiveFile
}
val archiveProvider =
project.tasks.named("zipXCFramework", Zip::class.java).flatMap {
it.archiveFile
}
artifact(archiveProvider) {
extension = "zip"
}
Expand Down Expand Up @@ -136,11 +131,14 @@ class SonatypePortalPublishArtifactManager(

// Either the user has supplied a correct name, or we use the default. If neither is found, fail.
val publicationNameCap =
publishingExtension.publications.getByName(
publicationName
).name.capitalized()

return publishingExtension.repositories.filterIsInstance<MavenArtifactRepository>()
publishingExtension.publications
.getByName(
publicationName,
).name
.capitalized()

return publishingExtension.repositories
.filterIsInstance<MavenArtifactRepository>()
.map { repo ->
val repositoryName = repo.name.capitalized()
val publishTaskName =
Expand Down Expand Up @@ -175,26 +173,27 @@ abstract class UpdatePackageSwiftChecksumTask : DefaultTask() {
}

// Compute the checksum
val checksum = zipFile.inputStream().use { input ->
val digest = MessageDigest.getInstance("SHA-256")
val buffer = ByteArray(8192)
var bytes = input.read(buffer)
while (bytes >= 0) {
digest.update(buffer, 0, bytes)
bytes = input.read(buffer)
val checksum =
zipFile.inputStream().use { input ->
val digest = MessageDigest.getInstance("SHA-256")
val buffer = ByteArray(8192)
var bytes = input.read(buffer)
while (bytes >= 0) {
digest.update(buffer, 0, bytes)
bytes = input.read(buffer)
}
digest.digest().joinToString("") { "%02x".format(it) }
}
digest.digest().joinToString("") { "%02x".format(it) }
}

// Update Package.swift
val packageSwiftFile = project.rootProject.file("Package.swift")
val updatedContent = packageSwiftFile.readText().replace(
Regex("let remoteKotlinChecksum = \"[a-f0-9]+\""),
"let remoteKotlinChecksum = \"$checksum\""
)
val updatedContent =
packageSwiftFile.readText().replace(
Regex("let remoteKotlinChecksum = \"[a-f0-9]+\""),
"let remoteKotlinChecksum = \"$checksum\"",
)
packageSwiftFile.writeText(updatedContent)

println("Updated Package.swift with new checksum: $checksum")
}
}

5 changes: 4 additions & 1 deletion PowerSync/src/iosMain/kotlin/com/powersync/SDK.kt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
@file:Suppress("ktlint:standard:no-empty-file")

// This is required to build the iOS framework
package com.powersync

package com.powersync
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ Demo applications are located in the [`demos/`](./demos) directory. See their re
- [demos/hello-powersync](./demos/hello-powersync/README.md): A minimal example demonstrating the use of the PowerSync Kotlin Multiplatform SDK and the Supabase connector.

- [demos/supabase-todolist](./demos/supabase-todolist/README.md): A simple to-do list application demonstrating the use of the PowerSync Kotlin Multiplatform SDK and the Supabase connector.
-
- [demos/android-supabase-todolist](./demos/android-supabase-todolist/README.md): A simple to-do list application demonstrating the use of the PowerSync Kotlin Multiplatform SDK and the Supabase connector in an Android application.

## Current Limitations / Future work
Expand Down Expand Up @@ -100,6 +99,11 @@ cocoapods {

Note: The `linkOnly` attribute is set to `true` and framework is set to `isStatic = true` to ensure that the `powersync-sqlite-core` binaries are only statically linked.

## Formatting and Linting

This repo uses [ktlint](https://pinterest.github.io/ktlint/) to handle formatting and linting. If you would like the IDE to automatically format your code and show linting errors install the [ktlint plugin](https://plugins.jetbrains.com/plugin/15057-ktlint). Then in Settings go to Tools -> Ktlint -> Select Distract free (recommended) mode.
It will automatically use the rules set in the `.editorconfig` file.

## Getting Started

Our [full SDK reference](https://docs.powersync.com/client-sdk-references/kotlin-multiplatform-alpha#getting-started) contains everything you need to know to get started implementing PowerSync in your project.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ plugins {
alias(libs.plugins.grammarKitComposer) apply false
alias(libs.plugins.mavenPublishPlugin) apply false
alias(libs.plugins.downloadPlugin) apply false
alias(libs.plugins.kotlinter) apply false
}

// Having different versions of this lead to the issue mentioned here
Expand All @@ -38,7 +39,6 @@ allprojects {
}
}


configurations.configureEach {
exclude(group = "com.jetbrains.rd")
exclude(group = "com.github.jetbrains", module = "jetCheck")
Expand Down
13 changes: 10 additions & 3 deletions compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.androidLibrary)
alias(libs.plugins.jetbrainsCompose)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlinter)
id("com.powersync.plugins.sonatype")
}

Expand Down Expand Up @@ -33,13 +34,19 @@ kotlin {

android {
namespace = "com.powersync.compose"
compileSdk = libs.versions.android.compileSdk.get().toInt()
compileSdk =
libs.versions.android.compileSdk
.get()
.toInt()
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
minSdk =
libs.versions.android.minSdk
.get()
.toInt()
}
kotlin {
jvmToolchain(17)
}
}

setupGithubRepository()
setupGithubRepository()
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import com.powersync.DatabaseDriverFactory


@Composable
public actual fun rememberDatabaseDriverFactory(): DatabaseDriverFactory {
val context = LocalContext.current
return remember {
DatabaseDriverFactory(context)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.powersync.DatabaseDriverFactory


@Composable
public actual fun rememberDatabaseDriverFactory(): DatabaseDriverFactory {
return remember {
public actual fun rememberDatabaseDriverFactory(): DatabaseDriverFactory =
remember {
DatabaseDriverFactory()
}
}
13 changes: 10 additions & 3 deletions connectors/supabase/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.kotlinSerialization)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.kotlinter)
id("com.powersync.plugins.sonatype")
}

Expand Down Expand Up @@ -37,13 +38,19 @@ kotlin {

android {
namespace = "com.powersync.connector.supabase"
compileSdk = libs.versions.android.compileSdk.get().toInt()
compileSdk =
libs.versions.android.compileSdk
.get()
.toInt()
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
minSdk =
libs.versions.android.minSdk
.get()
.toInt()
}
kotlin {
jvmToolchain(17)
}
}

setupGithubRepository()
setupGithubRepository()
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,42 @@ import kotlinx.coroutines.flow.StateFlow
*/
public class SupabaseConnector(
public val supabaseClient: SupabaseClient,
public val powerSyncEndpoint: String
public val powerSyncEndpoint: String,
) : PowerSyncBackendConnector() {

public constructor(
supabaseUrl: String,
supabaseKey: String,
powerSyncEndpoint: String
powerSyncEndpoint: String,
) : this(
supabaseClient = createSupabaseClient(supabaseUrl, supabaseKey) {
install(Auth)
install(Postgrest)
},
powerSyncEndpoint = powerSyncEndpoint
supabaseClient =
createSupabaseClient(supabaseUrl, supabaseKey) {
install(Auth)
install(Postgrest)
},
powerSyncEndpoint = powerSyncEndpoint,
)

init {
require(supabaseClient.pluginManager.getPluginOrNull(Auth) != null) { "The Auth plugin must be installed on the Supabase client" }
require(supabaseClient.pluginManager.getPluginOrNull(Postgrest) != null) { "The Postgrest plugin must be installed on the Supabase client" }
require(
supabaseClient.pluginManager.getPluginOrNull(Postgrest) != null,
) { "The Postgrest plugin must be installed on the Supabase client" }
}

public suspend fun login(email: String, password: String) {
public suspend fun login(
email: String,
password: String,
) {
supabaseClient.auth.signInWith(Email) {
this.email = email
this.password = password
}
}

public suspend fun signUp(email: String, password: String) {
public suspend fun signUp(
email: String,
password: String,
) {
supabaseClient.auth.signUpWith(Email) {
this.email = email
this.password = password
Expand All @@ -59,9 +67,7 @@ public class SupabaseConnector(
supabaseClient.auth.signOut()
}

public fun session(): UserSession? {
return supabaseClient.auth.currentSessionOrNull()
}
public fun session(): UserSession? = supabaseClient.auth.currentSessionOrNull()

public val sessionStatus: StateFlow<SessionStatus> = supabaseClient.auth.sessionStatus

Expand All @@ -84,7 +90,7 @@ public class SupabaseConnector(
return PowerSyncCredentials(
endpoint = powerSyncEndpoint,
token = session.accessToken, // Use the access token to authenticate against PowerSync
userId = session.user!!.id
userId = session.user!!.id,
)
}

Expand All @@ -95,12 +101,10 @@ public class SupabaseConnector(
* If this call throws an error, it is retried periodically.
*/
override suspend fun uploadData(database: PowerSyncDatabase) {

val transaction = database.getNextCrudTransaction() ?: return

var lastEntry: CrudEntry? = null
try {

for (entry in transaction.crud) {
lastEntry = entry

Expand Down Expand Up @@ -131,7 +135,6 @@ public class SupabaseConnector(
}

transaction.complete(null)

} catch (e: Exception) {
println("Data upload error - retrying last entry: ${lastEntry!!}, $e")
throw e
Expand Down
Loading
Loading