@@ -19,29 +19,18 @@ Build real-time, collaborative mobile apps that work seamlessly offline and auto
1919 No manual setup required — just access the full [ SQLite Sync API] ( https://github.com/sqliteai/sqlite-sync/blob/main/API.md ) directly through the ` writeDb ` / ` readDb ` instances.
2020
2121- 📱 ** Native-Only, Ultra-Fast**
22- Under the hood, we use OP-SQLite — a low-level, JSI-enabled SQLite engine for React Native With OP-SQLite, database operations run at near-native speed on iOS and Android.
22+ Under the hood, we use OP-SQLite — a low-level, JSI-enabled SQLite engine for React Native. With OP-SQLite, database operations run at near-native speed on iOS and Android.
2323
2424## 📚 Table of Contents
2525
2626- [ Requirements] ( #-requirements )
2727- [ Installation] ( #-installation )
2828- [ Quick Start] ( #-quick-start )
29+ - [ Sync Behavior] ( #-sync-behavior )
2930- [ API Reference] ( #-api-reference )
3031 - [ SQLiteSyncProvider] ( #sqlitesyncprovider )
3132 - [ Contexts] ( #contexts )
32- - [ SQLiteDbContext] ( #sqlitedbcontext )
33- - [ SQLiteSyncStatusContext] ( #sqlitesyncstatuscontext )
34- - [ SQLiteSyncActionsContext] ( #sqlitesyncactionscontext )
3533 - [ Hooks] ( #hooks )
36- - [ useSqliteDb] ( #usesqlitedb )
37- - [ useSyncStatus] ( #usesyncstatus )
38- - [ useSqliteSync] ( #usesqlitesync )
39- - [ useTriggerSqliteSync] ( #usetriggersqlitesync )
40- - [ useSqliteSyncQuery] ( #usesqlitesyncquery )
41- - [ useOnTableUpdate] ( #useontableupdate )
42- - [ useSqliteExecute] ( #usesqliteexecute )
43- - [ useSqliteTransaction] ( #usesqlitetransaction )
44- - [ Types] ( #types )
4534- [ Error Handling] ( #-error-handling )
4635- [ Debug Logging] ( #-debug-logging )
4736- [ Examples] ( #-examples )
@@ -251,11 +240,17 @@ Synchronization happens automatically in response to meaningful events:
251240- **App resume from background** → immediate sync (debounced to 5s)
252241- **Network reconnection** → immediate sync
253242
254- **Secondary Trigger (Polling Mode):**
243+ **Secondary Triggers:**
244+
245+ _Polling Mode:_
255246
256247- **Periodic polling while foreground** → interval adapts based on activity
257248- **No polling when backgrounded**
258249
250+ _Push Mode (Expo only):_
251+
252+ - **Push notification from SQLite Cloud** → immediate sync when changes detected on server
253+
259254### Adaptive Polling Algorithm
260255
261256In polling mode, the sync interval intelligently adjusts based on activity:
@@ -306,17 +301,20 @@ Main provider component that enables sync functionality.
306301
307302#### Props
308303
309- | Prop | Type | Required | Description |
310- | ------------------ | ----------------------- | -------- | -------------------------------------------------- |
311- | ` connectionString ` | ` string ` | ✅ | SQLite Cloud connection string |
312- | ` databaseName ` | ` string ` | ✅ | Local database file name |
313- | ` tablesToBeSynced ` | ` TableConfig []` | ✅ | Array of tables to sync |
314- | ` syncMode ` | ` ' polling' \| ' push' ` | ❌ | Sync mode (default: ` ' polling' ` ) |
315- | ` adaptivePolling ` | ` AdaptivePollingConfig ` | ❌ | Adaptive polling configuration (polling mode only) |
316- | ` apiKey ` | ` string ` | \* | API key for authentication |
317- | ` accessToken ` | ` string ` | \* | Access token for RLS authentication |
318- | ` debug ` | ` boolean ` | ❌ | Enable debug logging (default: ` false ` ) |
319- | ` children ` | ` ReactNode ` | ✅ | Child components |
304+ | Prop | Type | Required | Description |
305+ | ------------------------------- | --------------------------- | -------- | ---------------------------------------------------------- |
306+ | ` connectionString ` | ` string ` | ✅ | SQLite Cloud connection string |
307+ | ` databaseName ` | ` string ` | ✅ | Local database file name |
308+ | ` tablesToBeSynced ` | ` TableConfig []` | ✅ | Array of tables to sync |
309+ | ` apiKey ` | ` string ` | \* | API key for authentication |
310+ | ` accessToken ` | ` string ` | \* | Access token for RLS authentication |
311+ | ` syncMode ` | ` ' polling' \| ' push' ` | ❌ | Sync mode (default: ` ' polling' ` ) |
312+ | ` adaptivePolling ` | ` AdaptivePollingConfig ` | ❌ | Adaptive polling configuration (polling mode only) |
313+ | ` notificationListening ` | ` ' foreground' \| ' always' ` | ❌ | When to listen for push notifications (push mode only) |
314+ | ` onBeforePushPermissionRequest ` | ` () => Promise <boolean >` | ❌ | Custom UI before system permission prompt (push mode only) |
315+ | ` onDatabaseReady ` | ` (db : DB ) => Promise <void >` | ❌ | Callback after DB opens, before sync init (for migrations) |
316+ | ` debug ` | ` boolean ` | ❌ | Enable debug logging (default: ` false ` ) |
317+ | ` children ` | ` ReactNode ` | ✅ | Child components |
320318
321319\* Either ` apiKey ` or ` accessToken ` is required
322320
@@ -364,6 +362,63 @@ Uses push notifications from SQLite Cloud:
364362>
365363` ` `
366364
365+ #### Background Sync Callback (Push Mode)
366+
367+ When using push mode with ` notificationListening : ' always' ` , you can register a callback that runs after background sync completes. This is useful for showing local notifications about new data:
368+
369+ ` ` ` typescript
370+ import { registerBackgroundSyncCallback } from ' @sqliteai/sqlite-sync-react-native' ;
371+ import * as Notifications from ' expo-notifications' ;
372+
373+ // Register at module level (outside components)
374+ registerBackgroundSyncCallback (async ({ changes , db }) => {
375+ // Find new inserts in your table
376+ const newItems = changes .filter (
377+ (c ) => c .table === ' tasks' && c .operation === ' INSERT'
378+ );
379+
380+ if (newItems .length === 0 ) return ;
381+
382+ // Query the synced data
383+ const result = await db .execute (
384+ ` SELECT * FROM tasks WHERE rowid IN (${newItems .map ((c ) => c .rowId ).join (' ,' )}) `
385+ );
386+
387+ // Show a local notification
388+ await Notifications .scheduleNotificationAsync ({
389+ content: {
390+ title: ` ${newItems .length } new tasks synced ` ,
391+ body: result .rows ?.[0 ]?.title || ' New data available' ,
392+ },
393+ trigger: null ,
394+ });
395+ });
396+ ` ` `
397+
398+ #### Database Migrations with ` onDatabaseReady `
399+
400+ Use ` onDatabaseReady ` to run migrations or other setup after the database opens but before sync initialization:
401+
402+ ` ` ` typescript
403+ < SQLiteSyncProvider
404+ connectionString = " ..."
405+ databaseName = " myapp.db"
406+ apiKey = " ..."
407+ tablesToBeSynced = {[... ]}
408+ onDatabaseReady={async (db) => {
409+ // Check current schema version
410+ const { rows } = await db.execute('PRAGMA user_version');
411+ const version = rows?.[0 ]?.user_version ?? 0;
412+
413+ // Run migrations
414+ if (version < 1) {
415+ await db.execute('ALTER TABLE tasks ADD COLUMN priority INTEGER DEFAULT 0');
416+ await db.execute('PRAGMA user_version = 1');
417+ }
418+ }}
419+ >
420+ ```
421+
367422#### `AdaptivePollingConfig`
368423
369424Configuration for adaptive polling behavior (polling mode only).
@@ -1049,7 +1104,8 @@ Enable detailed logging during development:
10491104
10501105Check out the [examples](./examples) directory for complete working examples:
10511106
1052- - **[sync-demo](./examples/sync-demo)** - Basic sync demonstration with CRUD operations
1107+ - **[sync-demo-expo](./examples/sync-demo-expo)** - Expo development build with sync demonstration using push notifications
1108+ - **[sync-demo-bare](./examples/sync-demo-bare)** - Bare React Native project with sync demonstration using polling
10531109
10541110## 🔗 Links
10551111
0 commit comments