diff --git a/.github/workflows/dev-packages.yml b/.github/workflows/dev-packages.yml
index 424d0e8a..e63e2fe6 100644
--- a/.github/workflows/dev-packages.yml
+++ b/.github/workflows/dev-packages.yml
@@ -22,7 +22,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
- dotnet-version: "8.0.x"
+ dotnet-version: "10.0.x"
- name: Install MAUI Workloads
run: dotnet workload restore
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 8847ae65..71c0874a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -26,7 +26,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
with:
- dotnet-version: "8.0.x"
+ dotnet-version: "10.0.x"
- name: Install MAUI Workloads
run: dotnet workload restore
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 15bc561c..110b65f1 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,7 +18,7 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v5
with:
- dotnet-version: '8.0'
+ dotnet-version: '10.0'
- name: Install MAUI Workloads
run: dotnet workload restore
@@ -30,4 +30,4 @@ jobs:
run: dotnet restore
- name: Run tests
- run: dotnet test -v n --framework net8.0
\ No newline at end of file
+ run: dotnet test -v n --framework net10.0
diff --git a/Directory.build.props b/Directory.build.props
index fe14bb0e..0a2340a9 100644
--- a/Directory.build.props
+++ b/Directory.build.props
@@ -2,9 +2,6 @@
$(MSBuildWarningsAsMessages);NETSDK1202
- true
+ NU1500
-
-
-
diff --git a/IsExternalInit.cs b/IsExternalInit.cs
deleted file mode 100644
index 7d866a84..00000000
--- a/IsExternalInit.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using System.ComponentModel;
-
-namespace System.Runtime.CompilerServices
-{
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal class IsExternalInit { }
-}
diff --git a/PowerSync/PowerSync.Common/PowerSync.Common.csproj b/PowerSync/PowerSync.Common/PowerSync.Common.csproj
index 6e45bb7d..7310aa85 100644
--- a/PowerSync/PowerSync.Common/PowerSync.Common.csproj
+++ b/PowerSync/PowerSync.Common/PowerSync.Common.csproj
@@ -1,7 +1,9 @@
- netstandard2.0;net6.0;net8.0;net9.0;net8.0-ios;net8.0-android;net8.0-maccatalyst;net9.0-ios;net9.0-android;net9.0-maccatalyst
+ net8.0;net9.0;net10.0;net9.0-android;net10.0-android
+ $(TargetFrameworks);net9.0-ios;net10.0-ios;net9.0-maccatalyst;net10.0-maccatalyst
+
12
enable
enable
@@ -17,7 +19,8 @@
https://github.com/powersync-ja/powersync-dotnet/PowerSync/PowerSync.Common/CHANGELOG.md
powersync local-first local-storage state-management offline sql db persistence sqlite sync
icon.png
- NU5100
+ NU5100;1591
+ true
README.md
$(DefaultItemExcludes);runtimes/**/*.*;
@@ -27,21 +30,19 @@
-
-
-
-
-
-
+
+
+
+
+
-
-
+
diff --git a/PowerSync/PowerSync.Maui/PowerSync.Maui.csproj b/PowerSync/PowerSync.Maui/PowerSync.Maui.csproj
index 74e9a948..751532b2 100644
--- a/PowerSync/PowerSync.Maui/PowerSync.Maui.csproj
+++ b/PowerSync/PowerSync.Maui/PowerSync.Maui.csproj
@@ -1,7 +1,9 @@
- netstandard2.0;net6.0;net8.0;net9.0;net8.0-ios;net8.0-android;net8.0-maccatalyst;net9.0-ios;net9.0-android;net9.0-maccatalyst
+ net9.0;net10.0;net9.0-android;net10.0-android
+ $(TargetFrameworks);net9.0-ios;net10.0-ios;net9.0-maccatalyst;net10.0-maccatalyst
+
12
enable
enable
@@ -17,7 +19,7 @@
https://github.com/powersync-ja/powersync-dotnet/PowerSync/PowerSync.Maui/CHANGELOG.md
powersync local-first local-storage state-management offline sql db persistence sqlite sync
icon.png
- NU5100
+ NU5100;1591
README.md
true
true
diff --git a/README.md b/README.md
index b22b0a27..6f8d3334 100644
--- a/README.md
+++ b/README.md
@@ -110,13 +110,13 @@ dotnet restore
Run all tests
```bash
-dotnet test -v n --framework net8.0
+dotnet test -v n --framework net10.0
```
Run a specific test
```bash
-dotnet test -v n --framework net8.0 --filter "test-file-pattern"
+dotnet test -v n --framework net10.0 --filter "test-file-pattern"
```
### Integration Tests
@@ -125,13 +125,13 @@ Integration tests in `PowerSync.Common.IntegrationTests` are intended to run aga
The integration tests are disabled by default, define the following environment variable when running the tests.
```bash
-RUN_INTEGRATION_TESTS=true dotnet test -v n --framework net8.0
+RUN_INTEGRATION_TESTS=true dotnet test -v n --framework net10.0
```
Only run integration tests, without any unit tests.
```bash
-RUN_INTEGRATION_TESTS=true dotnet test -v n --framework net8.0 --filter "Category=Integration"
+RUN_INTEGRATION_TESTS=true dotnet test -v n --framework net10.0 --filter "Category=Integration"
```
### Performance Tests
@@ -139,13 +139,13 @@ RUN_INTEGRATION_TESTS=true dotnet test -v n --framework net8.0 --filter "Categor
Performance tests in `PowerSync.Common.PerformanceTests` are disabled by default, define the following environment variable when running the tests.
```bash
-RUN_PERFORMANCE_TESTS=true dotnet test -v n --framework net8.0
+RUN_PERFORMANCE_TESTS=true dotnet test -v n --framework net10.0
```
Only run performance tests, without any unit tests.
```bash
-RUN_PERFORMANCE_TESTS=true dotnet test -v n --framework net8.0 --filter "Category=Performance"
+RUN_PERFORMANCE_TESTS=true dotnet test -v n --framework net10.0 --filter "Category=Performance"
```
## Using the PowerSync.Common package in your project
diff --git a/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeClient.cs b/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeClient.cs
index dbd5073e..5ce805b7 100644
--- a/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeClient.cs
+++ b/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeClient.cs
@@ -1,161 +1,161 @@
-namespace PowerSync.Common.IntegrationTests;
-
-using System;
-using System.Collections.Generic;
-using System.Net.Http;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-
-using PowerSync.Common.DB.Crud;
-
-public class NodeClient
-{
- private readonly HttpClient _httpClient;
- private readonly string _backendUrl;
- private readonly string _userId;
-
- public NodeClient(string userId)
- {
- _httpClient = new HttpClient();
- _backendUrl = "http://localhost:6060";
- _userId = userId;
- }
-
- public NodeClient(string backendUrl, string userId)
- {
- _httpClient = new HttpClient();
- _backendUrl = backendUrl;
- _userId = userId;
- }
-
- public Task CreateList(string id, string name)
- {
- return CreateItem("lists", id, name);
- }
-
- async Task CreateItem(string table, string id, string name)
- {
- var data = new Dictionary
- {
- { "created_at", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") },
- { "name", name },
- { "owner_id", _userId }
- };
-
- var batch = new[]
- {
- new
- {
- op = UpdateType.PUT.ToString(),
- table = table,
- id = id,
- data = data
- }
- };
-
- var payload = JsonSerializer.Serialize(new { batch });
- var content = new StringContent(payload, Encoding.UTF8, "application/json");
-
- HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content);
-
- if (!response.IsSuccessStatusCode)
- {
- Console.WriteLine(await response.Content.ReadAsStringAsync());
- throw new Exception(
- $"Failed to create item. Status: {response.StatusCode}, " +
- $"Response: {await response.Content.ReadAsStringAsync()}"
- );
- }
-
- return await response.Content.ReadAsStringAsync();
- }
-
- public Task DeleteList(string id)
- {
- return DeleteItem("lists", id);
- }
-
- public Task CreateTodo(string id, string listId, string description)
- {
- return CreateTodoItem("todos", id, listId, description);
- }
-
- async Task CreateTodoItem(string table, string id, string listId, string description)
- {
- var data = new Dictionary
- {
- { "created_at", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") },
- { "description", description },
- { "list_id", listId },
- { "created_by", _userId },
- { "completed", 0 },
- };
-
- var batch = new[]
- {
- new
- {
- op = UpdateType.PUT.ToString(),
- table = table,
- id = id,
- data = data
- }
- };
-
- var payload = JsonSerializer.Serialize(new { batch });
- var content = new StringContent(payload, Encoding.UTF8, "application/json");
-
- HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content);
-
- if (!response.IsSuccessStatusCode)
- {
- Console.WriteLine(await response.Content.ReadAsStringAsync());
- throw new Exception(
- $"Failed to create todo. Status: {response.StatusCode}, " +
- $"Response: {await response.Content.ReadAsStringAsync()}"
- );
- }
-
- return await response.Content.ReadAsStringAsync();
- }
-
- public Task DeleteTodo(string id)
- {
- return DeleteItem("todos", id);
- }
-
- async Task DeleteItem(string table, string id)
- {
- var batch = new[]
- {
- new
- {
- op = UpdateType.DELETE.ToString(),
- table = table,
- id = id
- }
- };
-
- var payload = JsonSerializer.Serialize(new { batch });
- var content = new StringContent(payload, Encoding.UTF8, "application/json");
-
- HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content);
-
- if (!response.IsSuccessStatusCode)
- {
- Console.WriteLine(await response.Content.ReadAsStringAsync());
- throw new Exception(
- $"Failed to delete item. Status: {response.StatusCode}, " +
- $"Response: {await response.Content.ReadAsStringAsync()}"
- );
- }
-
- return await response.Content.ReadAsStringAsync();
- }
-
- public void Dispose()
- {
- _httpClient?.Dispose();
- }
+namespace PowerSync.Common.IntegrationTests;
+
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+using PowerSync.Common.DB.Crud;
+
+public class NodeClient
+{
+ private readonly HttpClient _httpClient;
+ private readonly string _backendUrl;
+ private readonly string _userId;
+
+ public NodeClient(string userId)
+ {
+ _httpClient = new HttpClient();
+ _backendUrl = "http://localhost:6060";
+ _userId = userId;
+ }
+
+ public NodeClient(string backendUrl, string userId)
+ {
+ _httpClient = new HttpClient();
+ _backendUrl = backendUrl;
+ _userId = userId;
+ }
+
+ public Task CreateList(string id, string name)
+ {
+ return CreateItem("lists", id, name);
+ }
+
+ async Task CreateItem(string table, string id, string name)
+ {
+ var data = new Dictionary
+ {
+ { "created_at", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") },
+ { "name", name },
+ { "owner_id", _userId }
+ };
+
+ var batch = new[]
+ {
+ new
+ {
+ op = UpdateType.PUT.ToString(),
+ table = table,
+ id = id,
+ data = data
+ }
+ };
+
+ var payload = JsonSerializer.Serialize(new { batch });
+ var content = new StringContent(payload, Encoding.UTF8, "application/json");
+
+ HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ Console.WriteLine(await response.Content.ReadAsStringAsync());
+ throw new Exception(
+ $"Failed to create item. Status: {response.StatusCode}, " +
+ $"Response: {await response.Content.ReadAsStringAsync()}"
+ );
+ }
+
+ return await response.Content.ReadAsStringAsync();
+ }
+
+ public Task DeleteList(string id)
+ {
+ return DeleteItem("lists", id);
+ }
+
+ public Task CreateTodo(string id, string listId, string description)
+ {
+ return CreateTodoItem("todos", id, listId, description);
+ }
+
+ async Task CreateTodoItem(string table, string id, string listId, string description)
+ {
+ var data = new Dictionary
+ {
+ { "created_at", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") },
+ { "description", description },
+ { "list_id", listId },
+ { "created_by", _userId },
+ { "completed", 0 },
+ };
+
+ var batch = new[]
+ {
+ new
+ {
+ op = UpdateType.PUT.ToString(),
+ table = table,
+ id = id,
+ data = data
+ }
+ };
+
+ var payload = JsonSerializer.Serialize(new { batch });
+ var content = new StringContent(payload, Encoding.UTF8, "application/json");
+
+ HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ Console.WriteLine(await response.Content.ReadAsStringAsync());
+ throw new Exception(
+ $"Failed to create todo. Status: {response.StatusCode}, " +
+ $"Response: {await response.Content.ReadAsStringAsync()}"
+ );
+ }
+
+ return await response.Content.ReadAsStringAsync();
+ }
+
+ public Task DeleteTodo(string id)
+ {
+ return DeleteItem("todos", id);
+ }
+
+ async Task DeleteItem(string table, string id)
+ {
+ var batch = new[]
+ {
+ new
+ {
+ op = UpdateType.DELETE.ToString(),
+ table = table,
+ id = id
+ }
+ };
+
+ var payload = JsonSerializer.Serialize(new { batch });
+ var content = new StringContent(payload, Encoding.UTF8, "application/json");
+
+ HttpResponseMessage response = await _httpClient.PostAsync($"{_backendUrl}/api/data", content);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ Console.WriteLine(await response.Content.ReadAsStringAsync());
+ throw new Exception(
+ $"Failed to delete item. Status: {response.StatusCode}, " +
+ $"Response: {await response.Content.ReadAsStringAsync()}"
+ );
+ }
+
+ return await response.Content.ReadAsStringAsync();
+ }
+
+ public void Dispose()
+ {
+ _httpClient?.Dispose();
+ }
}
diff --git a/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeConnector.cs b/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeConnector.cs
index ae2a1b2b..6585a42b 100644
--- a/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeConnector.cs
+++ b/Tests/PowerSync/PowerSync.Common.IntegrationTests/NodeConnector.cs
@@ -1,114 +1,114 @@
-namespace PowerSync.Common.IntegrationTests;
-
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net.Http;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-
-using PowerSync.Common.Client;
-using PowerSync.Common.Client.Connection;
-using PowerSync.Common.DB.Crud;
-
-
-public class NodeConnector : IPowerSyncBackendConnector
-{
- private readonly HttpClient _httpClient;
-
- public string BackendUrl { get; }
- public string PowerSyncUrl { get; }
- public string UserId { get; private set; }
- private string? clientId;
-
- public NodeConnector(string userId)
- {
- _httpClient = new HttpClient();
-
- // Load or generate User ID
- UserId = userId;
-
- BackendUrl = "http://localhost:6060";
- PowerSyncUrl = "http://localhost:8080";
-
- clientId = null;
- }
-
- public async Task FetchCredentials()
- {
- string tokenEndpoint = "api/auth/token";
- string url = $"{BackendUrl}/{tokenEndpoint}?user_id={UserId}";
-
- HttpResponseMessage response = await _httpClient.GetAsync(url);
- if (!response.IsSuccessStatusCode)
- {
- throw new Exception($"Received {response.StatusCode} from {tokenEndpoint}: {await response.Content.ReadAsStringAsync()}");
- }
-
- string responseBody = await response.Content.ReadAsStringAsync();
- var jsonResponse = JsonSerializer.Deserialize>(responseBody);
-
- if (jsonResponse == null || !jsonResponse.ContainsKey("token"))
- {
- throw new Exception("Invalid response received from authentication endpoint.");
- }
-
- return new PowerSyncCredentials(PowerSyncUrl, jsonResponse["token"]);
- }
-
- public async Task UploadData(IPowerSyncDatabase database)
- {
- CrudTransaction? transaction;
- try
- {
- transaction = await database.GetNextCrudTransaction();
- }
- catch (Exception ex)
- {
- Console.WriteLine($"UploadData Error: {ex.Message}");
- return;
- }
-
- if (transaction == null)
- {
- return;
- }
-
- clientId ??= await database.GetClientId();
-
- try
- {
- var batch = new List