subgraph-sync
Version:
React hooks and components for tracking subgraph synchronization states with Apollo Client
275 lines (214 loc) • 6.79 kB
Markdown
# Subgraph Sync
A React library for handling subgraph synchronization states with Apollo Client. Track indexing progress, sync states, and ensure your dApp queries return up-to-date data from The Graph.
[](#tests)
[](#coverage)
[](https://www.typescriptlang.org/)
[](LICENSE)
## Features
- 🔄 **Real-time Sync Tracking** - Monitor subgraph indexing progress
- 🎯 **Block & Timestamp Targeting** - Wait for specific blocks or timestamps
- ⚡ **Progress Calculation** - Visual progress indicators (0-100%)
- 🔁 **Automatic Retries** - Configurable retry logic for failed queries
- ⏱️ **Timeout Handling** - Graceful timeout with callbacks
- 🎨 **UI Components** - Pre-built React components for sync indicators
- 📦 **Context Provider** - Manage multiple transaction sync states
- � **Type-Safe** - Full TypeScript support
- 🔒 **Type-Safe** - Full TypeScript support
## Installation
```bash
npm install subgraph-sync
# or
yarn add subgraph-sync
# or
pnpm add subgraph-sync
```
### Peer Dependencies
This library requires the following peer dependencies:
```json
{
"@apollo/client": "^3.0.0",
"graphql": "^15.0.0 || ^16.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
```
## Quick Start
### Basic Usage with useSubgraphSync
```tsx
import { useSubgraphSync } from "subgraph-sync";
function MyComponent() {
const syncState = useSubgraphSync(
{ blockNumber: 1000000 }, // Target block
{ pollInterval: 2000 } // Poll every 2 seconds
);
if (syncState.isIndexing) {
return <div>Syncing... {syncState.progress}%</div>;
}
if (syncState.isSynced) {
return <div>✅ Synced to block {syncState.currentBlock?.number}</div>;
}
return null;
}
```
### Combined Query + Sync
```tsx
import { gql } from "@apollo/client";
import { useSubgraphQuery } from "subgraph-sync";
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
balance
}
}
`;
function UserBalance({ userId, targetBlock }) {
const { data, loading, isIndexing, isSynced, progress } = useSubgraphQuery(
GET_USER,
{
variables: { id: userId },
targetBlockNumber: targetBlock,
}
);
if (loading || isIndexing) {
return <div>Loading... {progress}%</div>;
}
return <div>Balance: {data.user.balance}</div>;
}
```
### Using the SyncIndicator Component
```tsx
import { useSubgraphSync, SyncIndicator } from "subgraph-sync";
function TransactionTracker({ txHash, blockNumber }) {
const syncState = useSubgraphSync({ blockNumber });
return (
<div>
<h2>Transaction: {txHash}</h2>
<SyncIndicator
syncState={syncState}
showProgress={true}
showBlockInfo={true}
/>
</div>
);
}
```
## API Reference
### `useSubgraphSync(target, config?)`
Track subgraph synchronization to a specific target.
**Parameters:**
- `target: SyncTarget` - Target block or timestamp
- `blockNumber?: number` - Target block number
- `timestamp?: number` - Target timestamp
- `config?: SyncConfig` - Optional configuration
- `pollInterval?: number` - Polling interval in ms (default: 2000)
- `timeout?: number` - Timeout in ms (default: 120000)
- `maxRetries?: number` - Max retry attempts (default: 3)
- `onTimeout?: () => void` - Timeout callback
- `onError?: (error: Error) => void` - Error callback
- `onSyncComplete?: (status: SubgraphStatus) => void` - Success callback
**Returns:** `UseSubgraphSyncResult`
```typescript
{
isIndexing: boolean; // Currently indexing
isSynced: boolean; // Reached target
isTimeout: boolean; // Timed out
isError: boolean; // Error occurred
currentBlock: Block | null; // Current indexed block
targetBlock: Block | null; // Target block
progress: number; // Progress 0-100
error: string | null; // Error message
retries: number; // Retry count
refetch: () => Promise<any>; // Manual refetch
reset: () => void; // Reset state
}
```
### `useSubgraphQuery(query, options?)`
Combines Apollo `useQuery` with sync tracking.
**Parameters:**
- `query: DocumentNode` - GraphQL query
- `options?: QueryWithSyncOptions` - Apollo query options + sync options
- `targetBlockNumber?: number` - Target block
- `targetTimestamp?: number` - Target timestamp
- `syncConfig?: SyncConfig` - Sync configuration
- ...all Apollo `useQuery` options
**Returns:** All Apollo `QueryResult` properties + `UseSubgraphSyncResult` properties
### `<SyncIndicator />`
Pre-built UI component for displaying sync state.
**Props:**
```typescript
{
syncState: UseSubgraphSyncResult; // Required: sync state
showProgress?: boolean; // Show progress bar (default: true)
showBlockInfo?: boolean; // Show block details (default: true)
className?: string; // Additional CSS classes
}
```
## Examples
### Wait for Transaction Confirmation
```tsx
import { useSubgraphSync } from "subgraph-sync";
function SendTransaction() {
const [targetBlock, setTargetBlock] = useState(null);
const syncState = useSubgraphSync(
{ blockNumber: targetBlock },
{
onSyncComplete: () => {
console.log("Transaction indexed!");
},
}
);
return (
<div>
<button onClick={() => setTargetBlock(1000000)}>Send Transaction</button>
{syncState.isIndexing && (
<div>Waiting for indexing... {syncState.progress}%</div>
)}
</div>
);
}
```
### Custom Error Handling
```tsx
const syncState = useSubgraphSync(
{ blockNumber: 1000000 },
{
maxRetries: 5,
pollInterval: 1000,
timeout: 60000,
onError: (error) => {
console.error("Sync failed:", error);
},
onTimeout: () => {
console.warn("Sync timeout");
},
}
);
```
## Testing
```bash
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage report
```
## TypeScript
Full TypeScript definitions included:
```typescript
import type {
SyncConfig,
SyncTarget,
SyncState,
UseSubgraphSyncResult,
SubgraphStatus,
Block,
QueryWithSyncOptions,
} from "subgraph-sync";
```
## License
MIT
This library provides:
- **Modular architecture** for easy extension
- **TypeScript support** for better developer experience
- **Flexible configuration** for different use cases
- **Pre-built components** for quick integration
- **Comprehensive documentation** for easy adoption
- **Build system** for distribution