- Add support for loading custom SQLite extensions via
MDSQLiteOptions.Extensions. - Fix streaming sync retry loop reconnecting with no delay after an exception, ignoring
RetryDelayMs.
- Add support for MacCatalyst.
- Add support for .NET 9.0. Supported targets now also include
net9.0,net9.0-android,net9.0-ios, andnet9.0-maccatalyst. - Update the PowerSync SQLite core extension to 0.4.13.
- Add support for offline-first file attachments via
AttachmentQueue. SeeAttachments/README.md.
- Support Windows ARM.
- Update the PowerSync SQLite core extension to 0.4.12.
- Beta release.
- Implemented throttling for
Watch<T>andOnChange(default 30ms). StatusUpdatedandStatusChangednow both emitSyncStatusobjects instead of justStatusChanged.- Converted most instances of a class inheriting from
EventStream<T>into a class with anEventManagerproperty calledEvents. This allows for subscribing to individual events instead of subscribing to all events and then filtering events manually.
// Old
var listener = db.Listen(cts.Token);
foreach (PowerSyncDBEvent update in listener)
{
// Manually filter updates
if (update.StatusChanged != null)
{
Console.WriteLine("status changed: " + update.StatusChanged!);
}
}
// Old (async)
var listener = db.ListenAsync(cts.Token);
await foreach (PowerSyncDBEvent update in listener)
{
// Manually filter updates
if (update.StatusChanged != null)
{
Console.WriteLine("status changed: " + update.StatusChanged!);
}
}
// New
var listener = db.Events.OnStatusChanged.Listen(cts.Token);
await foreach (PowerSyncDBEvents.StatusChanged update in listener)
{
// Events are filtered inherently
Console.WriteLine("status changed: " + update.Status);
}
// New (async) - recommended for most use cases
var listener = db.Events.OnStatusChanged.ListenAsync(cts.Token);
await foreach (PowerSyncDBEvents.StatusChanged update in listener)
{
// Events are filtered inherently
Console.WriteLine("status changed: " + update.Status);
}- Pool read connections in
MDSQLiteAdapter, improving performance in any case where multiple queries run simultaneously (eg. viaWatch). The number of connections can be set viaMDSQLiteOptions.ReadPoolSizeand defaults to 5. - Updated to the latest version (0.4.11) of the core extension.
MDSQLiteConnectionnow runs query operations on another thread, which stops the caller thread from blocking.- Removed the
RunListenerandRunListenerAsyncAPIs fromIEventStream. Users are encouraged to use theListenorListenAsyncAPIs instead (RunListeneritself was implemented using theListenAPI). - Changed the
PowerSyncDatabase.Watchsyntax to return an IAsyncEnumerable instead of accepting a callback. This allows users to handle database changes when they are ready instead of us eagerly running the callback as soon as a change is detected.
// Optional cancellation token
var cts = new CancellationTokenSource();
// Register listener synchronously on the calling thread...
var listener = db.Watch<Todo>(
"SELECT * FROM todos",
[],
new SQLWatchOptions { Signal = cts.Token }
);
// ...then listen to changes on another thread
_ = Task.Run(async () =>
{
await foreach (var result in listener)
{
Console.WriteLine($"Number of todos: {result.Length}");
}
}, cts.Token);
// Stop watching by cancelling token
cts.Cancel();- Fixed watched queries sometimes resolving to the wrong underlying tables after a schema change.
- Fixed some properties in Table not being public when they are meant to be.
- Fixed a bug where custom indexes were not being sent to the PowerSync SQLite extension.
- Added a new model-based syntax for defining the PowerSync schema (the old syntax is still functional). This syntax uses classes marked with attributes to define the PowerSync schema. The classes can then also be used for queries later on.
using PowerSync.Common.DB.Schema;
using PowerSync.Common.DB.Schema.Attributes;
[
Table("todos"),
Index("list", ["list_id"])
]
public class Todo
{
[Column("id")]
public string TodoId { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("description")]
public string? Description { get; set; }
[Column("completed")]
public bool Completed { get; set; }
}
public class Schema
{
public static Schema AppSchema = new Schema(typeof(Todo));
}
// Usage
var todos = powerSync.GetAll<Todo>("SELECT * FROM todos");- Breaking: Further updated schema definition syntax.
- Renamed
SchemaandTabletoCompiledSchemaandCompiledTableand renamedSchemaFactoryandTableFactorytoSchemaandTable. - Made
CompiledSchemaandCompiledTableinternal classes. - These are the last breaking changes to schema definition before entering beta.
- Renamed
public static Table Assets = new Table
{
Name = "assets",
Columns =
{
["make"] = ColumnType.Text,
["model"] = ColumnType.Text,
// ...
},
Indexes =
{
["makemodel"] = ["make", "model"],
},
};
public static Table Customers = new Table
{
Name = "customers",
Columns =
{
["name"] = ColumnType.Text,
},
};
public static Schema PowerSyncSchema = new Schema(Assets, Customers);- Updated the syntax for defining the app schema to use a factory pattern.
- Add support for sync streams.
- Return an
IDisposablefromPowerSync.Watch, allowing for easier cancellation of watched queries. - Replaced the old JSON-based method of extracting type information from queries with using Dapper internally for queries, improving memory usage and execution time for querying.
- Added non-generic overloads for
GetAll(),GetOptional(),Get(),Watch()which returndynamic:
dynamic asset = db.Get("SELECT id, description, make FROM assets");
Console.WriteLine($"Asset ID: {asset.id}");- Added fallback to check the application's root directory for the PowerSync extension - fixing compatibility with WPF/WAP, .NET Framework <= 4.8, and other platforms that flatten DLLs into the base folder.
- Added
ExecuteBatch()implementation. - Added
GetUploadQueueStats()toPowerSyncDatabase. - Altered query methods,
Execute(),GetAll(),GetOptional(),Get(),Watch(), to support null parameters in their parameters list, for example:
db.Execute(
"INSERT INTO assets(id, description, make) VALUES(?, ?, ?)",
[id, name, null] // last parameter is an explicit null value
);- Updated to the latest version (0.4.10) of the core extension.
- Dropping support for the legacy C# sync implementation.
- Add
trackPreviousValuesoption onTableOptionswhich setsCrudEntry.PreviousValuesto previous values on updates. - Add
trackMetadataoption onTableOptionswhich adds a_metadatacolumn that can be used for updates. The configured metadata is available throughCrudEntry.Metadata. - Add
ignoreEmptyUpdatesoption onTableOptionswhich skips creating CRUD entries for updates that don't change any values. - Reporting progress information about downloaded rows. Sync progress is available through
SyncStatus.DownloadProgress(). - Support bucket priorities.
- Report
PriorityStatusEntriesonSyncStatus. - Added ability to specify
AppMetadatafor sync/stream requests.
Note: This requires a PowerSync service version >=1.17.0 in order for logs to display metadata.
db.Connect(connector, new PowerSync.Common.Client.Sync.Stream.PowerSyncConnectionOptions
{
// This will be included in PowerSync service logs
AppMetadata = new Dictionary<string, string>
{
{ "app_version", myAppVersion },
}
});- Using the latest version (0.4.9) of the core extension, it introduces support for the Rust Sync implementation and also makes it the default - users can still opt out and use the legacy C# sync implementation as option when calling
connect().
- Fixed MAUI issues related to extension loading when installing package outside of the monorepo.
- Minor changes to accommodate PowerSync.MAUI package extension.
- Updated core extension to v0.3.14
- Loading last synced time from core extension
- Expose upload and download errors on SyncStatus
- Improved credentials management and error handling. Credentials are invalidated when they expire or become invalid based on responses from the PowerSync service. The frequency of credential fetching has been reduced as a result of this work.
- Introduce package. Support for Desktop .NET use cases.
- linux-arm64
- linux-x64
- osx-arm64
- osx-x64
- wind-x64