@@ -60,6 +60,7 @@ private RequiredMDSQLiteOptions ResolveMDSQLiteOptions(MDSQLiteOptions? options)
6060 LockTimeoutMs = options ? . LockTimeoutMs ?? defaults . LockTimeoutMs ,
6161 EncryptionKey = options ? . EncryptionKey ?? defaults . EncryptionKey ,
6262 Extensions = options ? . Extensions ?? defaults . Extensions ,
63+ LoadPowerSyncExtension = options ? . LoadPowerSyncExtension ?? defaults . LoadPowerSyncExtension ,
6364 ReadPoolSize = options ? . ReadPoolSize ?? defaults . ReadPoolSize ,
6465 } ;
6566 }
@@ -105,7 +106,7 @@ private async Task Init()
105106 }
106107 return readConnection ;
107108 } ;
108- readPool = new MDSQLiteConnectionPool ( resolvedOptions , readConnectionFactory ) ;
109+ readPool = new MDSQLiteConnectionPool ( resolvedOptions . ReadPoolSize , readConnectionFactory ) ;
109110 await readPool . Init ( ) ;
110111
111112 // Register TablesUpdated listener
@@ -125,10 +126,25 @@ private async Task Init()
125126 protected async Task < MDSQLiteConnection > OpenConnection ( string dbFilename )
126127 {
127128 var db = OpenDatabase ( dbFilename ) ;
128- LoadExtension ( db ) ;
129+ LoadExtensions ( db ) ;
129130
130131 var connection = new MDSQLiteConnection ( new MDSQLiteConnectionOptions ( db ) ) ;
131- await connection . Execute ( "SELECT powersync_init()" ) ;
132+ try
133+ {
134+ await connection . Execute ( "SELECT powersync_init()" ) ;
135+ }
136+ catch ( SqliteException ex )
137+ {
138+ // SQLite will throw a very unhelpful "SQLite Error 1: 'The specified
139+ // module could not be found.'" error if uncaught.
140+ throw new SqliteException (
141+ "Failed to initialize PowerSync: powersync_init() is not registered. " +
142+ "Ensure the PowerSync core SQLite extension is loaded. Either set " +
143+ "MDSQLiteOptions.LoadPowerSyncExtension to true (default), or supply " +
144+ "a PowerSync-compatible extension via MDSQLiteOptions.Extensions." ,
145+ ex . SqliteErrorCode ,
146+ ex . SqliteExtendedErrorCode ) ;
147+ }
132148
133149 return connection ;
134150 }
@@ -141,11 +157,28 @@ private static SqliteConnection OpenDatabase(string dbFilename)
141157 return connection ;
142158 }
143159
144- protected virtual void LoadExtension ( SqliteConnection db )
160+ protected virtual void LoadExtensions ( SqliteConnection db )
145161 {
146- string extensionPath = PowerSyncPathResolver . GetNativeLibraryPath ( AppContext . BaseDirectory ) ;
147162 db . EnableExtensions ( true ) ;
148- db . LoadExtension ( extensionPath , "sqlite3_powersync_init" ) ;
163+ if ( resolvedOptions . LoadPowerSyncExtension )
164+ {
165+ LoadDefaultPowerSyncExtension ( db ) ;
166+ }
167+ foreach ( var extension in resolvedOptions . Extensions )
168+ {
169+ db . LoadExtension ( extension . Path , extension . EntryPoint ) ;
170+ }
171+ }
172+
173+ /// <summary>
174+ /// Loads the bundled PowerSync core SQLite extension. Override on
175+ /// platform-specific adapters (e.g. MAUI iOS/Android) where the native library
176+ /// lives outside the desktop runtime path.
177+ /// </summary>
178+ protected virtual void LoadDefaultPowerSyncExtension ( SqliteConnection db )
179+ {
180+ var path = PowerSyncPathResolver . GetNativeLibraryPath ( AppContext . BaseDirectory ) ;
181+ db . LoadExtension ( path , "sqlite3_powersync_init" ) ;
149182 }
150183
151184 public async Task Close ( )
@@ -301,18 +334,16 @@ await readPool.LeaseAll(async (connections) =>
301334
302335class MDSQLiteConnectionPool
303336{
304- private readonly RequiredMDSQLiteOptions _options ;
305337 private readonly Channel < MDSQLiteConnection > _channel ;
306338 private readonly int _poolSize ;
307339 private readonly Func < Task < MDSQLiteConnection > > _connectionFactory ;
308340
309341 private readonly Task _initialized ;
310342
311- public MDSQLiteConnectionPool ( RequiredMDSQLiteOptions options , Func < Task < MDSQLiteConnection > > connectionFactory )
343+ public MDSQLiteConnectionPool ( int poolSize , Func < Task < MDSQLiteConnection > > connectionFactory )
312344 {
313- _options = options ;
314- _channel = Channel . CreateBounded < MDSQLiteConnection > ( options . ReadPoolSize ) ;
315- _poolSize = options . ReadPoolSize ;
345+ _channel = Channel . CreateBounded < MDSQLiteConnection > ( poolSize ) ;
346+ _poolSize = poolSize ;
316347 _connectionFactory = connectionFactory ;
317348 _initialized = Initialize ( ) ;
318349 }
@@ -364,32 +395,6 @@ public async Task LeaseAll(Func<List<MDSQLiteConnection>, Task> callback)
364395 }
365396 }
366397
367- private async Task < MDSQLiteConnection > OpenConnection ( string dbFilename )
368- {
369- var db = OpenDatabase ( dbFilename ) ;
370- LoadExtension ( db ) ;
371-
372- var connection = new MDSQLiteConnection ( new MDSQLiteConnectionOptions ( db ) ) ;
373- await connection . Execute ( "SELECT powersync_init()" ) ;
374-
375- return connection ;
376- }
377-
378- private static SqliteConnection OpenDatabase ( string dbFilename )
379- {
380- string connectionString = $ "Data Source={ dbFilename } ;Pooling=False;";
381- var connection = new SqliteConnection ( connectionString ) ;
382- connection . Open ( ) ;
383- return connection ;
384- }
385-
386- private void LoadExtension ( SqliteConnection db )
387- {
388- string extensionPath = PowerSyncPathResolver . GetNativeLibraryPath ( AppContext . BaseDirectory ) ;
389- db . EnableExtensions ( true ) ;
390- db . LoadExtension ( extensionPath , "sqlite3_powersync_init" ) ;
391- }
392-
393398 public async Task Close ( )
394399 {
395400 await LeaseAll ( ( connections ) =>
0 commit comments