
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
react-offline-sync-hook
Advanced tools
A comprehensive React hook for offline data synchronization with automatic conflict resolution and queue management
The website will work even when the network is offline.
A comprehensive React hook for offline data synchronization with automatic conflict resolution, queue management, and background sync capabilities.
useOfflineSync (core)<OfflineSyncProvider>npm install react-offline-sync-hook
# or
yarn add react-offline-sync-hook
# or
pnpm add react-offline-sync-hook
import React from "react";
import { OfflineSyncProvider, useOfflineSync } from "react-offline-sync-hook";
// 1. Configure the sync behavior
const config = {
storageAdapter: "indexedDB",
apiEndpoint: "https://your-api.com/api/todos",
retryAttempts: 3,
conflictResolution: "last-write-wins",
enableBackgroundSync: true,
};
// 2. Create your component
const TodoApp = () => {
const { data, addItem, updateItem, deleteItem, status } = useOfflineSync(
"todos",
config
);
return (
<div>
<div>Status: {status.isOnline ? "🟢 Online" : "🔴 Offline"}</div>
<button onClick={() => addItem({ title: "New Todo", completed: false })}>
Add Todo
</button>
{data.map((todo) => (
<div key={todo.id}>
{todo.title}
<button onClick={() => deleteItem(todo.id)}>Delete</button>
</div>
))}
</div>
);
};
// 3. Wrap with Provider
const App = () => (
<OfflineSyncProvider config={config}>
<TodoApp />
</OfflineSyncProvider>
);
interface SyncConfig {
// Storage
storageAdapter: "localStorage" | "indexedDB";
// API
apiEndpoint: string;
headers?: Record<string, string>;
// Retry Logic
retryAttempts?: number; // Default: 3
retryDelay?: number; // Default: 1000ms
// Batching
batchSize?: number; // Default: 10
// Conflict Resolution
conflictResolution?:
| "client-wins"
| "server-wins"
| "last-write-wins"
| "custom";
customConflictHandler?: (local: any, remote: any) => any;
// Background Sync
enableBackgroundSync?: boolean; // Default: false
syncInterval?: number; // Auto-sync interval in ms
}
const {
data, // T[] - Your synchronized data
status, // SyncStatus - Current sync state
error, // Error | null - Last error
syncNow, // () => Promise<void> - Manual sync
addItem, // (item: Omit<T, 'id'>) => Promise<void>
updateItem, // (id: string, updates: Partial<T>) => Promise<void>
deleteItem, // (id: string) => Promise<void>
clearData, // () => Promise<void>
} = useOfflineSync<T>(key, config, initialData);
interface SyncStatus {
isOnline: boolean; // Network connectivity
isSyncing: boolean; // Currently syncing
lastSync: Date | null; // Last successful sync
pendingItems: number; // Items waiting to sync
error: string | null; // Last error message
}
const config = {
conflictResolution: "custom",
customConflictHandler: (localData, remoteData) => {
// Your custom merge logic
return {
...localData,
...remoteData,
title: `${localData.title} (merged)`,
updatedAt: new Date().toISOString(),
};
},
};
// 1. Enable in config
const config = {
enableBackgroundSync: true,
// ... other options
};
// 2. Create service worker file: public/offline-sync-sw.js
// (The package provides a generator for this)
const todosSync = useOfflineSync<Todo>("todos", todosConfig);
const notesSync = useOfflineSync<Note>("notes", notesConfig);
const contactsSync = useOfflineSync<Contact>("contacts", contactsConfig);
const config = { storageAdapter: "localStorage" };
const config = { storageAdapter: "indexedDB" };
The hook automatically detects network changes:
const { status } = useOfflineSync("data", config);
// React to network changes
useEffect(() => {
if (status.isOnline) {
console.log("Back online! Auto-syncing...");
} else {
console.log("Gone offline. Queuing changes...");
}
}, [status.isOnline]);
Built-in exponential backoff:
const config = {
retryAttempts: 5, // Try 5 times
retryDelay: 1000, // Start with 1 second
// Delays: 1s, 2s, 4s, 8s, 16s
};
const { error, status } = useOfflineSync("data", config);
// Handle errors
if (error) {
console.error("Sync error:", error.message);
}
// Check sync status
if (status.error) {
console.warn("Last sync failed:", status.error);
}
// pages/_app.tsx or app/layout.tsx
import { OfflineSyncProvider } from "react-offline-sync-hook";
export default function App({ Component, pageProps }) {
return (
<OfflineSyncProvider config={syncConfig}>
<Component {...pageProps} />
</OfflineSyncProvider>
);
}
// src/index.tsx
import { OfflineSyncProvider } from "react-offline-sync-hook";
ReactDOM.render(
<OfflineSyncProvider config={syncConfig}>
<App />
</OfflineSyncProvider>,
document.getElementById("root")
);
// app/root.tsx
import { OfflineSyncProvider } from "react-offline-sync-hook";
export default function App() {
return (
<html>
<head />
<body>
<OfflineSyncProvider config={syncConfig}>
<Outlet />
</OfflineSyncProvider>
</body>
</html>
);
}
npm test # Run tests
npm run test:watch # Watch mode
# Development
npm run dev
# Build
npm run build
# Lint
npm run lint
# Type check
npm run type-check
# Publish
npm publish
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)MIT © Biren Gohel
Made with ❤️ for the Biren Gohel
FAQs
A comprehensive React hook for offline data synchronization with automatic conflict resolution and queue management
We found that react-offline-sync-hook demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.