offline-sync-queue
v0.1.1
Published
Reusable offline sync queue package (IOfflineQueue contract with WatermelonDB implementation) for React Native apps
Maintainers
Readme
offline-sync-queue
A reusable offline sync queue for React Native (bare/CLI, not Expo) apps. Actions taken while offline are persisted locally with WatermelonDB and automatically retried — with backoff — once the device is back online.
App code depends only on the IOfflineQueue contract, never on the WatermelonDB implementation
directly, so the storage/sync engine can be swapped later without touching consuming screens.
Installation
npm install offline-sync-queue @nozbe/watermelondbreact and react-native are peer dependencies — your app already has them.
Usage
1. Create a queue
import { createOfflineQueueDatabase, WatermelonOfflineQueue } from 'offline-sync-queue';
const database = createOfflineQueueDatabase({ dbName: 'my_app_queue' });
export const offlineQueue = new WatermelonOfflineQueue(database);2. Register a handler for each operation type
The package doesn't know or care what you're syncing — you register the network call for each
operation type:
offlineQueue.registerHandler<{ orderId: string; items: string[] }>(
'CREATE_ORDER',
async (operation) => {
await fetch('https://myapi.com/orders', {
method: 'POST',
body: JSON.stringify(operation.payload),
});
}
);3. (Optional) Plug in your own network detection
By default the queue assumes it's always online. Inject a NetworkMonitor to make it
connectivity-aware:
import type { NetworkMonitor } from 'offline-sync-queue';
import NetInfo from '@react-native-community/netinfo';
const networkMonitor: NetworkMonitor = {
isConnected: async () => (await NetInfo.fetch()).isConnected ?? false,
onChange: (listener) => NetInfo.addEventListener((state) => listener(!!state.isConnected)),
};
const offlineQueue = new WatermelonOfflineQueue(database, {
networkMonitor,
autoProcessIntervalMs: 30_000, // optional: also retry on a timer while online
});
offlineQueue.start();4. Enqueue actions from anywhere in your app
await offlineQueue.enqueue(
'CREATE_ORDER',
{ orderId: '123', items: ['sku-1'] },
{ maxRetries: 5 } // optional, defaults to 3
);5. Bind it to your UI with the hook
import { useOfflineQueue } from 'offline-sync-queue';
function SyncBadge() {
const { pending, failed, isSyncing, sync } = useOfflineQueue(offlineQueue);
return (
<Text onPress={sync}>
{isSyncing ? 'Syncing…' : `${pending.length} pending, ${failed.length} failed`}
</Text>
);
}API
| Export | What it is |
| --- | --- |
| IOfflineQueue | The core contract — implement this to swap out the storage/sync engine. |
| WatermelonOfflineQueue | The WatermelonDB-backed implementation of IOfflineQueue. |
| NetworkMonitor | Interface for connectivity detection. NoopNetworkMonitor (always "online") is the default. |
| createOfflineQueueDatabase(options) | Creates a standalone WatermelonDB Database for the queue table. |
| useOfflineQueue(queue) | React hook exposing { pending, failed, isSyncing, enqueue, sync, refresh }. |
| QueuedOperation, SyncStatus, QueueEvent, ... | Supporting types for the contract above. |
See src/types.ts for the full IOfflineQueue method signatures.
How retries work
Each failed operation increments a retry count and is retried with exponential backoff
(1s, 2s, 4s, ... capped at 30s) until maxRetries is reached, after which it's marked failed
and left for the app to inspect (or discard, via dequeue) rather than retried forever.
Contributing
License
MIT
Made with create-react-native-library
