Skip to content
Open
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: 1 addition & 2 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ jobs:

- name: Restore Projects
run: |
dotnet restore PowerSync/PowerSync.Common/PowerSync.Common.csproj -p:TargetFrameworks=net8.0
dotnet restore PowerSync/PowerSync.Maui/PowerSync.Maui.csproj -p:TargetFrameworks=net8.0
dotnet restore PowerSync/PowerSync.Common/PowerSync.Common.csproj -p:TargetFrameworks=net10.0

- name: Generate API Metadata
working-directory: docs
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ jobs:

- name: Restore Projects
run: |
dotnet restore PowerSync/PowerSync.Common/PowerSync.Common.csproj -p:TargetFrameworks=net8.0
dotnet restore PowerSync/PowerSync.Maui/PowerSync.Maui.csproj -p:TargetFrameworks=net8.0
dotnet restore PowerSync/PowerSync.Common/PowerSync.Common.csproj -p:TargetFrameworks=net10.0

- name: Generate API Metadata
working-directory: docs
Expand Down
29 changes: 3 additions & 26 deletions .github/workflows/dev-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
with:
dotnet-version: "10.0.x"

- name: Install MAUI Workloads
- name: Install native workloads
run: dotnet workload restore

- name: Download PowerSync extension
Expand All @@ -33,9 +33,6 @@ jobs:
- name: Restore dependencies
run: dotnet restore

- name: Install Android SDK for net8.0-android
run: dotnet build PowerSync/PowerSync.Common -t:InstallAndroidDependencies -f net8.0-android -p:AndroidSdkDirectory="$ANDROID_HOME" -p:AcceptAndroidSdkLicenses=True

- name: Extract Common Package Version from CHANGELOG.md
shell: bash
run: |
Expand All @@ -50,20 +47,6 @@ jobs:
- name: Run Pack For Common
run: dotnet pack PowerSync/PowerSync.Common -c Release -o ${{ github.workspace }}/output

- name: Extract MAUI Package Version from CHANGELOG.md
shell: bash
run: |
MAUI_VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+-dev(\.[0-9]+)?$/ {print $2; exit}' PowerSync/PowerSync.Maui/CHANGELOG.md)
if [[ -z "$MAUI_VERSION" ]]; then
echo "Error: Invalid dev version found in PowerSync.Maui/CHANGELOG.md. Expected format: x.x.x-dev.x"
exit 1
fi
echo "Detected Version: $MAUI_VERSION"
echo "VERSION=$MAUI_VERSION" >> $GITHUB_ENV

- name: Run Pack For MAUI
run: dotnet pack PowerSync/PowerSync.Maui -c Release -o ${{ github.workspace }}/output

- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
Expand All @@ -90,7 +73,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
dotnet-version: "10.0.x"

- name: Install Sign CLI tool
run: dotnet tool install --tool-path . --prerelease sign
Expand Down Expand Up @@ -142,7 +125,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
dotnet-version: "10.0.x"

- name: Validate artifact signatures
run: dotnet nuget verify ${{ github.workspace }}/SignedArtifacts/**/*.nupkg
Expand All @@ -158,9 +141,3 @@ jobs:
dotnet nuget push "${{ github.workspace }}\SignedArtifacts\PowerSync.Common*.nupkg"
--api-key "${{ steps.login.outputs.NUGET_API_KEY }}"
--source https://api.nuget.org/v3/index.json

- name: Run Push For Maui
run: >
dotnet nuget push "${{ github.workspace }}\SignedArtifacts\PowerSync.Maui*.nupkg"
--api-key "${{ steps.login.outputs.NUGET_API_KEY }}"
--source https://api.nuget.org/v3/index.json
47 changes: 3 additions & 44 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ jobs:

outputs:
common_version: ${{ steps.extract_version.outputs.common_version }}
maui_version: ${{ steps.extract_maui_version.outputs.maui_version }}

steps:
- name: Checkout Repository
Expand All @@ -28,7 +27,7 @@ jobs:
with:
dotnet-version: "10.0.x"

- name: Install MAUI Workloads
- name: Install native workloads
run: dotnet workload restore

- name: Download PowerSync extension
Expand All @@ -37,9 +36,6 @@ jobs:
- name: Restore dependencies
run: dotnet restore

- name: Install Android SDK for net8.0-android
run: dotnet build PowerSync/PowerSync.Common -t:InstallAndroidDependencies -f net8.0-android -p:AndroidSdkDirectory="$ANDROID_HOME" -p:AcceptAndroidSdkLicenses=True

- name: Extract Common Package Version from CHANGELOG.md
id: extract_version
shell: bash
Expand All @@ -56,22 +52,6 @@ jobs:
- name: Run Pack For Common
run: dotnet pack PowerSync/PowerSync.Common -c Release -o ${{ github.workspace }}/output

- name: Extract MAUI Package Version from CHANGELOG.md
id: extract_maui_version
shell: bash
run: |
MAUI_VERSION=$(awk '/^## [0-9]+\.[0-9]+\.[0-9]+/ {print $2; exit}' PowerSync/PowerSync.Maui/CHANGELOG.md)
if [[ -z "$MAUI_VERSION" ]]; then
echo "Error: Invalid version found in PowerSync.Maui/CHANGELOG.md. Expected format: '## x.x.x'"
exit 1
fi
echo "Detected Version: $MAUI_VERSION"
echo "VERSION=$MAUI_VERSION" >> $GITHUB_ENV
echo "maui_version=$MAUI_VERSION" >> $GITHUB_OUTPUT

- name: Run Pack For MAUI
run: dotnet pack PowerSync/PowerSync.Maui -c Release -o ${{ github.workspace }}/output

- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
Expand All @@ -98,7 +78,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
dotnet-version: "10.0.x"

- name: Install Sign CLI tool
run: dotnet tool install --tool-path . --prerelease sign
Expand Down Expand Up @@ -150,7 +130,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
dotnet-version: "10.0.x"

- name: Validate artifact signatures
run: dotnet nuget verify ${{ github.workspace }}/SignedArtifacts/**/*.nupkg
Expand Down Expand Up @@ -181,24 +161,3 @@ jobs:
--target main \
--generate-notes \
SignedArtifacts/PowerSync.Common*.nupkg

- name: Run Push For Maui
run: >
dotnet nuget push "${{ github.workspace }}\SignedArtifacts\PowerSync.Maui*.nupkg"
--api-key "${{ steps.login.outputs.NUGET_API_KEY }}"
--source https://api.nuget.org/v3/index.json

- name: Create GitHub Release For Maui
continue-on-error: true
shell: bash
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
MAUI_VERSION: ${{ needs.build.outputs.maui_version }}
run: |
gh release create "PowerSync.Maui@${MAUI_VERSION}" \
--draft \
--title "PowerSync.Maui@${MAUI_VERSION}" \
--target main \
--generate-notes \
SignedArtifacts/PowerSync.Maui*.nupkg
12 changes: 6 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
jobs:
build:
strategy:
matrix:
matrix:
runner: [windows-latest, windows-11-arm]
name: Test Packages ${{ matrix.runner }}
runs-on: ${{ matrix.runner }}
Expand All @@ -18,16 +18,16 @@ jobs:
- name: Setup .NET SDK
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0'
dotnet-version: "10.0"

- name: Install MAUI Workloads
- name: Install native workloads
run: dotnet workload restore

- name: Download PowerSync extension
run: dotnet run --project Tools/Setup
run: dotnet run --project Tools/Setup

- name: Restore dependencies
run: dotnet restore

- name: Run tests
run: dotnet test -v n --framework net10.0
10 changes: 3 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,14 @@ TestResults/
*.VSIXProjectLaunch
.project
.vsconfig
.env

*.db
*.db-shm
*.db-wal

#Core binaries - add rules after ps extension downloading is supported
*.dylib
*.dll
*.so
*.xcframework
.env
*NativeLibs
# PowerSync runtimes installed by Tools/Setup
**/runtimes/

# Ignore user id file
user_id.txt
Expand Down
3 changes: 2 additions & 1 deletion PowerSync/PowerSync.Common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

- Full release.
- `PowerSyncDatabase.OnChange` now returns the underlying raw table name instead of the view name to mirror PowerSync JS.
- Use `long` for op IDs instead of `string`. This affects the types returned by some methods used in `PowerSyncBackendConnector.UploadData`, namely `PowerSyncDatabase.GetNextCrudTransaction()` and `PowerSyncDatabase.GetCrudBatch()`.
- Use `long` for op IDs instead of `string`. This affects the types returned by some methods used in `PowerSyncBackendConnector.UploadData`, namely `PowerSyncDatabase.GetNextCrudTransaction()` and `PowerSyncDatabase.GetCrudBatch()`, as well as `ICustomCheckpointRequestConnector.PostCheckpointRequest`.
- Bundle and load native libraries on Android, iOS, and MacCatalyst. This allows `PowerSync.Common` to fully replace `PowerSync.Maui`.

## 1.0.0 (unlisted)

Expand Down
52 changes: 34 additions & 18 deletions PowerSync/PowerSync.Common/Client/PowerSyncDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ public class PowerSyncDatabase : IPowerSyncDatabase

protected IBucketStorageAdapter BucketStorageAdapter;

private readonly object currentStatusLock = new();
/// <summary>
/// The latest published sync status.
/// </summary>
public SyncStatus CurrentStatus { get; protected set; }

protected CancellationTokenSource masterCts = new();
Expand All @@ -163,6 +167,7 @@ public class PowerSyncDatabase : IPowerSyncDatabase
public ILogger Logger { get; protected set; }

private readonly AsyncLock runExclusive = new();

private readonly Func<IPowerSyncBackendConnector, Remote> remoteFactory;

public StreamingSyncImplementation? SyncStreamImplementation => ConnectionManager.SyncStreamImplementation;
Expand Down Expand Up @@ -225,6 +230,8 @@ public PowerSyncDatabase(PowerSyncDatabaseOptions options)
await WaitForReady();
using (await runExclusive.LockAsync())
{
var syncStreamStatusCts = CancellationTokenSource.CreateLinkedTokenSource(masterCts.Token);

syncStreamImplementation = new StreamingSyncImplementation(new StreamingSyncImplementationOptions
{
Adapter = BucketStorageAdapter,
Expand All @@ -245,20 +252,22 @@ public PowerSyncDatabase(PowerSyncDatabaseOptions options)
Subscriptions = options.Subscriptions,
CrudUploadThrottleMs = options.CrudUploadThrottleMs,
TimeProvider = timeProvider,
Logger = Logger
});

var syncStreamStatusCts = CancellationTokenSource.CreateLinkedTokenSource(masterCts.Token);
var syncStreamStatusListener = syncStreamImplementation.Events.OnStatusChanged.ListenAsync(syncStreamStatusCts.Token);
var _ = Task.Run(async () =>
{
await foreach (var update in syncStreamStatusListener)
Logger = Logger,
OnStatusChanged = status =>
{
CurrentStatus = new SyncStatus(new SyncStatusOptions(update.Status.Options)
if (syncStreamStatusCts.IsCancellationRequested)
{
HasSynced = CurrentStatus?.HasSynced == true || update.Status.LastSyncedAt != null,
});
Events.Emit(new PowerSyncDBEvents.StatusChangedEvent(CurrentStatus));
return;
}

lock (currentStatusLock)
{
CurrentStatus = new SyncStatus(new SyncStatusOptions(status.Options)
{
HasSynced = CurrentStatus?.HasSynced == true || status.LastSyncedAt != null,
});
Events.Emit(new PowerSyncDBEvents.StatusChangedEvent(CurrentStatus));
}
}
});

Expand Down Expand Up @@ -431,12 +440,16 @@ protected async Task ResolveOfflineSyncStatus()
var parsed = JsonConvert.DeserializeObject<CoreSyncStatus>(result.r);

var parsedSyncStatus = CoreInstructionHelpers.CoreStatusToSyncStatus(parsed!);
var updatedStatus = CurrentStatus.CreateUpdatedStatus(parsedSyncStatus);

if (!updatedStatus.IsEqual(CurrentStatus))
lock (currentStatusLock)
{
CurrentStatus = updatedStatus;
Events.Emit(new PowerSyncDBEvents.StatusChangedEvent(CurrentStatus));
var updatedStatus = CurrentStatus.CreateUpdatedStatus(parsedSyncStatus);

if (!updatedStatus.IsEqual(CurrentStatus))
{
CurrentStatus = updatedStatus;
Events.Emit(new PowerSyncDBEvents.StatusChangedEvent(CurrentStatus));
}
}
}

Expand Down Expand Up @@ -522,8 +535,11 @@ await Database.WriteTransaction(async tx =>
});

// The data has been deleted - reset the sync status
CurrentStatus = new SyncStatus(new SyncStatusOptions());
Events.Emit(new PowerSyncDBEvents.StatusChangedEvent(CurrentStatus));
lock (currentStatusLock)
{
CurrentStatus = new SyncStatus(new SyncStatusOptions());
Events.Emit(new PowerSyncDBEvents.StatusChangedEvent(CurrentStatus));
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using PowerSync.Common.DB.Crud;
using PowerSync.Common.Utils;
using PowerSync.Common.Utils.Converters;

public static class PowerSyncControlCommand
{
Expand All @@ -34,13 +35,15 @@
public class Checkpoint
{
[JsonProperty("last_op_id")]
public string LastOpId { get; set; } = null!;
[JsonConverter(typeof(StringLongConverter))]
public long LastOpId { get; set; }

[JsonProperty("buckets")]
public BucketChecksum[] Buckets { get; set; } = [];

[JsonProperty("write_checkpoint")]
public string? WriteCheckpoint { get; set; } = null;
[JsonConverter(typeof(StringLongConverter))]
public long? WriteCheckpoint { get; set; } = null;

[JsonProperty("streams")]
public object[]? Streams { get; set; } = [];
Expand Down Expand Up @@ -144,7 +147,7 @@
/// <summary>
/// Increments and returns the local checkpoint counter.
/// </summary>
public async Task<long> NextCheckpointRequestId() => (long)await ReadOrUpdateCheckpoint("next");

Check warning on line 150 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-11-arm

Nullable value type may be null.

Check warning on line 150 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-11-arm

Nullable value type may be null.

Check warning on line 150 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-latest

Nullable value type may be null.

Check warning on line 150 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-latest

Nullable value type may be null.

/// <summary>
/// Returns the highest checkpoint request ID that has been requested on this device.
Expand All @@ -171,7 +174,7 @@
/// </item>
/// </list>
/// </summary>
public async Task<long> SeedCheckpointRequestId(long serviceResponse) => (long)await ReadOrUpdateCheckpoint("seed", serviceResponse);

Check warning on line 177 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-11-arm

Nullable value type may be null.

Check warning on line 177 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-11-arm

Nullable value type may be null.

Check warning on line 177 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-latest

Nullable value type may be null.

Check warning on line 177 in PowerSync/PowerSync.Common/Client/Sync/Bucket/BucketStorageAdapter.cs

View workflow job for this annotation

GitHub Actions / Test Packages windows-latest

Nullable value type may be null.

/// <summary>
/// Get a unique client ID.
Expand Down
Loading
Loading