Now.js Framework Documentation

Now.js Framework Documentation

SyncManager

EN 15 Dec 2025 06:25

SyncManager

Overview

SyncManager is the synchronization system for offline data in Now.js Framework. It supports queue, priorities, and automatic retry.

When to use:

  • Need offline-first application
  • Need to queue pending operations
  • Need to sync data when back online
  • Need priority-based sync

Why use it:

  • ✅ Offline queue management
  • ✅ Priority-based synchronization
  • ✅ Automatic retry with backoff
  • ✅ Network status monitoring
  • ✅ Integration with ApiService
  • ✅ Event-based system
  • ✅ Enable/disable functionality

Basic Usage

Initialization

await SyncManager.init({
  enabled: true,
  autoSync: true,
  syncInterval: 60000, // 1 minute
  endpoints: {
    users: '/api/users',
    orders: '/api/orders',
    products: '/api/products'
  }
});

Add Pending Operations

// Add operation to sync later
await SyncManager.addPendingOperation({
  storeName: 'orders',
  method: 'add',
  data: {
    customer_id: 123,
    items: [...],
    total: 1500
  },
  priority: 'high'
});

// Update operation
await SyncManager.addPendingOperation({
  storeName: 'users',
  method: 'update',
  data: { id: 1, name: 'John Updated' },
  priority: 'medium'
});

// Delete operation
await SyncManager.addPendingOperation({
  storeName: 'products',
  method: 'delete',
  data: { id: 5 },
  priority: 'low'
});

Manual Sync

// Sync all pending operations
const results = await SyncManager.syncAll();
console.log('Synced:', results.successful);
console.log('Failed:', results.failed);

Configuration

await SyncManager.init({
  // Enable/disable sync
  enabled: true,

  // Auto sync settings
  autoSync: true,
  syncInterval: 60000,     // Sync interval (ms)

  // Retry settings
  retryStrategy: 'exponential', // 'exponential', 'linear', 'fixed'
  maxRetries: 5,

  // Parallel processing
  maxConcurrentRequests: 3,

  // Endpoints mapping
  endpoints: {
    users: '/api/users',
    orders: '/api/orders'
  },

  // Storage
  pendingOperationsStore: 'sync_pending_operations',

  // Callbacks
  onSyncComplete: (results) => {
    console.log('Sync completed:', results);
  },
  onSyncError: (error) => {
    console.error('Sync error:', error);
  }
});

Priority Levels

Priority Description
high Process first, critical operations
medium Normal priority (default)
low Process last, non-urgent operations
// High priority - process first
await SyncManager.addPendingOperation({
  storeName: 'payments',
  method: 'add',
  data: paymentData,
  priority: 'high'
});

// Low priority - process last
await SyncManager.addPendingOperation({
  storeName: 'analytics',
  method: 'add',
  data: analyticsData,
  priority: 'low'
});

Retry Strategies

Exponential Backoff (default)

// Retry intervals: 1s, 2s, 4s, 8s, 16s...
retryStrategy: 'exponential'

Linear Backoff

// Retry intervals: 1s, 2s, 3s, 4s, 5s...
retryStrategy: 'linear'

Fixed Interval

// Retry intervals: 5s, 5s, 5s, 5s, 5s...
retryStrategy: 'fixed'

Network Detection

SyncManager automatically detects network status:

// Listens for online/offline events
window.addEventListener('online', () => {
  // Auto-sync when back online (if enabled)
});

window.addEventListener('offline', () => {
  // Queue operations for later
});

API Reference

SyncManager.init(options)

Initialize SyncManager

Parameter Type Description
options object Configuration options

Returns: Promise<SyncManager>

SyncManager.enable()

Enable synchronization

SyncManager.enable();

SyncManager.disable()

Disable synchronization

SyncManager.disable();

SyncManager.addPendingOperation(operation)

Add operation to queue

Parameter Type Description
operation.storeName string Store/resource name
operation.method string 'add', 'update', 'delete'
operation.data object Data to sync
operation.priority string 'high', 'medium', 'low'

Returns: Promise<Object> - Created operation

SyncManager.syncAll()

Sync all pending operations

Returns: Promise<Object> - Results:

{
  successful: number,
  failed: number,
  skipped: number,
  details: [...]
}

SyncManager.getPendingOperations()

Get all pending operations

Returns: Promise<Array>

SyncManager.getPendingCount()

Get pending operations count

Returns: Promise<number>

SyncManager.getFailedOperations()

Get failed operations

Returns: Promise<Array>

SyncManager.resetFailedOperations()

Reset failed operations to pending

Returns: Promise<number> - Number of operations reset

SyncManager.clearPendingOperations()

Clear all pending operations

Returns: Promise<boolean>

SyncManager.deletePendingOperation(id)

Delete specific operation

Parameter Type Description
id number Operation ID

Returns: Promise<boolean>

SyncManager.getSyncStatus()

Get current sync status

Returns: Object:

{
  enabled: boolean,
  syncing: boolean,
  lastSyncTime: Date,
  pendingCount: number,
  failedCount: number,
  online: boolean
}

SyncManager.startAutoSync()

Start automatic synchronization

SyncManager.stopAutoSync()

Stop automatic synchronization

Events

Event When Triggered Detail
sync:started Sync started {count}
sync:complete Sync completed {successful, failed}
sync:error Sync error {error, operation}
sync:online Back online -
sync:offline Went offline -
EventManager.on('sync:complete', (data) => {
  NotificationManager.success(`Synced ${data.successful} items`);
});

EventManager.on('sync:error', (data) => {
  console.error('Sync failed:', data.error);
});

Real-World Examples

Offline Form Submission

// Initialize sync
await SyncManager.init({
  enabled: true,
  autoSync: true,
  endpoints: {
    orders: '/api/orders'
  }
});

// Form submission
async function submitOrder(formData) {
  if (navigator.onLine) {
    // Online: submit directly
    try {
      await ApiService.post('/api/orders', formData);
      NotificationManager.success('Order submitted');
    } catch (error) {
      // Network error: queue for later
      await queueOrder(formData);
    }
  } else {
    // Offline: queue for later
    await queueOrder(formData);
  }
}

async function queueOrder(data) {
  await SyncManager.addPendingOperation({
    storeName: 'orders',
    method: 'add',
    data,
    priority: 'high'
  });

  // Also save locally
  await StorageManager.add('offline_orders', data);

  NotificationManager.info('Order saved. Will sync when online.');
}

Sync Status UI

<div id="sync-status">
  <span class="sync-indicator"></span>
  <span class="sync-text">Data is up to date</span>
</div>

<script>
async function updateSyncUI() {
  const status = SyncManager.getSyncStatus();
  const indicator = document.querySelector('.sync-indicator');
  const text = document.querySelector('.sync-text');

  if (status.syncing) {
    indicator.className = 'sync-indicator syncing';
    text.textContent = 'Syncing...';
  } else if (status.pendingCount > 0) {
    indicator.className = 'sync-indicator pending';
    text.textContent = `${status.pendingCount} items pending sync`;
  } else if (!status.online) {
    indicator.className = 'sync-indicator offline';
    text.textContent = 'Offline';
  } else {
    indicator.className = 'sync-indicator synced';
    text.textContent = 'Data is up to date';
  }
}

// Update UI on events
EventManager.on('sync:started', updateSyncUI);
EventManager.on('sync:complete', updateSyncUI);
EventManager.on('sync:online', updateSyncUI);
EventManager.on('sync:offline', updateSyncUI);
</script>

Retry Failed Operations

// Get failed operations
const failed = await SyncManager.getFailedOperations();

if (failed.length > 0) {
  const retry = await DialogManager.confirm(
    `${failed.length} operations failed to sync. Retry?`
  );

  if (retry) {
    await SyncManager.resetFailedOperations();
    await SyncManager.syncAll();
  }
}

Common Pitfalls

⚠️ 1. Check Network Status

// ❌ Not checking online status
SyncManager.syncAll();

// ✅ Check first
if (navigator.onLine) {
  SyncManager.syncAll();
} else {
  console.log('Offline - will sync later');
}

⚠️ 2. Handle Conflicts

// Server may reject due to stale data
SyncManager.init({
  onSyncError: async (error, operation) => {
    if (error.status === 409) { // Conflict
      // Fetch latest and merge
      const latest = await ApiService.get(`/api/${operation.storeName}/${operation.data.id}`);
      // ... resolve conflict
    }
  }
});

⚠️ 3. Unique Operation IDs

// SyncManager generates IDs automatically
// But if you need custom IDs:
await SyncManager.addPendingOperation({
  id: `order_${orderId}_${Date.now()}`,
  storeName: 'orders',
  method: 'add',
  data: orderData
});