Reliable offline-first request queue for web & Node.js apps
๐ฎ Live Interactive Demo | ๐ฆ npm Package | ๐ป Demo Source
Queue HTTP requests when offline and automatically sync them when the network reconnects. Perfect for PWAs, mobile apps, fintech, delivery apps, and any application requiring reliable data persistence.
- ๐ Automatic Sync - Detects network changes and syncs queued requests
- ๐ฆ Persistent Storage - IndexedDB (50MB+), LocalStorage, or Memory adapters
- ๐ฏ Priority Queue - High, normal, low priority levels
- โป๏ธ Smart Retry Logic - Exponential backoff with configurable max retries
- ๐ช Lifecycle Hooks -
onSuccess,onFailure,onRetrycallbacks - ๐ Universal - Works in browser and Node.js environments
- ๐จ Framework Agnostic - Use with React, Vue, Angular, or vanilla JS
- ๐ TypeScript First - Full type definitions included
- ๐ชถ Lightweight - Minimal dependencies
npm install offline-queue-engineTry it live: Interactive Demo
import { OfflineQueueEngine } from 'offline-queue-engine';
// Create queue instance
const queue = new OfflineQueueEngine({
hooks: {
onSuccess: (item) => console.log('โ
Synced:', item),
onFailure: (item, error) => console.error('โ Failed:', error),
onRetry: (item, count) => console.log('๐ Retry attempt:', count)
}
});
// Add requests to queue
await queue.add({
url: '/api/orders',
method: 'POST',
body: { item: 'Pizza', quantity: 2 },
priority: 'high'
});That's it! Requests are automatically:
- โ Persisted to IndexedDB
- โ Sent when online
- โ Retried on failure
- โ Synced on reconnect
new OfflineQueueEngine(config?: QueueConfig)Options:
| Option | Type | Default | Description |
|---|---|---|---|
storage |
StorageAdapter |
IndexedDBStore |
Storage adapter (IndexedDB, LocalStorage, Memory) |
hooks |
Hooks |
{} |
Lifecycle callbacks |
autoSync |
boolean |
true |
Auto-sync on network reconnect |
maxRetries |
number |
5 |
Maximum retry attempts |
Add a request to the queue.
await queue.add({
url: '/api/save',
method: 'POST',
body: { name: 'John' },
headers: { 'Authorization': 'Bearer token' },
priority: 'high' // 'high' | 'normal' | 'low'
});Manually trigger queue processing.
await queue.sync();Get current queue size.
const pending = queue.size();
console.log(`${pending} requests pending`);Clear all queued requests.
await queue.clear();Check network status.
if (queue.isOnline()) {
console.log('Connected');
}Cleanup and remove event listeners.
queue.destroy();// Ensure payment requests are never lost
await queue.add({
url: '/api/payments',
method: 'POST',
body: { amount: 99.99, userId: '123' },
priority: 'high'
});// Save form data offline
await queue.add({
url: '/api/leads',
method: 'POST',
body: formData,
priority: 'normal'
});// Queue messages when offline
await queue.add({
url: '/api/messages',
method: 'POST',
body: { text: 'Hello!', chatId: '456' },
priority: 'high'
});import { OfflineQueueEngine, LocalStorageStore } from 'offline-queue-engine';
const queue = new OfflineQueueEngine({
storage: new LocalStorageStore()
});const queue = new OfflineQueueEngine({
hooks: {
onSuccess: (item) => {
console.log('Request succeeded:', item.url);
// Update UI, show notification, etc.
},
onFailure: (item, error) => {
console.error('Request failed permanently:', error);
// Log to error tracking service
},
onRetry: (item, retryCount) => {
console.log(`Retry ${retryCount} for ${item.url}`);
// Show retry indicator in UI
}
},
maxRetries: 3,
autoSync: true
});import { shouldRetry, calculateBackoff } from 'offline-queue-engine';
// Check if request should retry
const retry = shouldRetry(500, 2, 5); // status, retryCount, maxRetries
// Calculate exponential backoff
const delay = calculateBackoff(2, 1000); // retryCount, baseDelay (ms)
// Returns: 4000ms (1s * 2^2)import { useEffect, useState } from 'react';
import { OfflineQueueEngine } from 'offline-queue-engine';
function App() {
const [queue] = useState(() => new OfflineQueueEngine({
hooks: {
onSuccess: () => console.log('Synced!')
}
}));
const handleSubmit = async (data) => {
await queue.add({
url: '/api/data',
method: 'POST',
body: data
});
};
useEffect(() => {
return () => queue.destroy();
}, []);
return <form onSubmit={handleSubmit}>...</form>;
}import { OfflineQueueEngine } from 'offline-queue-engine';
export default {
data() {
return {
queue: new OfflineQueueEngine()
};
},
methods: {
async submitForm(data) {
await this.queue.add({
url: '/api/data',
method: 'POST',
body: data
});
}
},
beforeUnmount() {
this.queue.destroy();
}
};For testing, use the MemoryStore adapter:
import { OfflineQueueEngine, MemoryStore } from 'offline-queue-engine';
const queue = new OfflineQueueEngine({
storage: new MemoryStore() // Non-persistent, fast
});| Adapter | Capacity | Persistent | Async | Best For |
|---|---|---|---|---|
| IndexedDBStore | 50MB+ | โ Yes | โ Yes | Production apps (default) |
| LocalStorageStore | ~5-10MB | โ Yes | โ No | Simple apps, small queues |
| MemoryStore | RAM only | โ No | โ Yes | Testing, development |
The engine uses smart retry logic:
- โ Retries: Network errors, 5xx server errors
- โ No retry: 4xx client errors (bad request, auth, etc.)
- ๐ Exponential backoff: 1s โ 2s โ 4s โ 8s โ 16s (max 30s)
- ๐ Max retries: 5 attempts by default (configurable)
Most offline queue solutions are:
- โ Framework-specific
- โ Heavyweight
- โ Complex to configure
- โ Poor TypeScript support
offline-queue-engine is:
- โ Universal (browser + Node.js)
- โ Lightweight (~5KB gzipped)
- โ Simple API
- โ Full TypeScript support
- โ Production-tested
MIT ยฉ Sahil Laskar
Contributions welcome! Please open an issue or PR.
The live demo includes 6 comprehensive examples:
- ๐ Basic Usage - Simple queuing and offline handling
- ๐ฏ Priority Queue - High/Normal/Low priority demonstration
- โป๏ธ Retry Logic - Smart retry with exponential backoff
- ๐พ Storage Adapters - Memory/LocalStorage/IndexedDB comparison
- ๐ช Lifecycle Hooks - Event tracking and callbacks
- โก Advanced Features - Batch operations, custom headers, manual sync
Demo Source Code: github.com/Sakil9051/demo-offline-queue
Built with โค๏ธ for offline-first applications