"Subscriptions"
Subscribe to queries and receive realtime updates when data changes.
How subscriptions work
Tether uses WebSocket connections to push updates to clients. When you subscribe to a query, you receive the initial data immediately, then automatic updates whenever a mutation affects the subscribed data.
Flow:
- Client subscribes to query — the client opens a WebSocket connection and registers a subscription.
- Initial data returned — the server immediately responds with the current query result.
- Updates pushed on changes — whenever a mutation affects the subscribed data, the server pushes an update.
Subscribing in Vue/Nuxt
Use the useQuery composable for reactive subscriptions. It's auto-imported by the Nuxt module:
// This automatically subscribes and updates when data changes
const { data, isLoading, error } = useQuery('todos.list', { completed: false });
Subscribing in React
Use the vanilla client's subscribe method with React's useEffect. The React SDK is in development.
import { useEffect, useState } from 'react';
import { tether } from '../lib/tether';
function TodoList() {
const [todos, setTodos] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = tether.subscribe(
'todos.list',
{ completed: false },
(data) => {
setTodos(data);
setLoading(false);
}
);
return () => unsubscribe();
}, []);
if (loading) return <p>Loading...</p>;
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
Manual subscriptions
For more control, use the low-level subscription API:
import { TetherClient } from '@tthr/client';
const client = new TetherClient({
url: 'https://tether-api.yourdomain.com',
projectId: 'your-project-id',
authToken: () => getAuthToken(), // optional
});
// Subscribe to a query
const unsubscribe = client.subscribe(
'todos.list',
{ completed: false },
(data) => {
console.log('Todos updated:', data);
}
);
// Unsubscribe when done
unsubscribe();
Update behaviour
Subscription updates are complete snapshots, not diffs. When data changes, you receive the full query result. This simplifies client-side state management and ensures consistency.
Connection resilience
Tether automatically handles connection issues with built-in resilience features.
Heartbeat
The client sends periodic ping messages every 30 seconds to detect connection health. If no response is received within 10 seconds, the client automatically reconnects.
Automatic reconnection
On disconnection, the client reconnects with exponential backoff:
| Attempt | Delay |
|---|---|
| Attempt 1 | 1 second |
| Attempt 2 | 2 seconds |
| Attempt 3 | 4 seconds |
| Attempt 4 | 8 seconds |
| Attempt 5 | 16 seconds |
Sync on reconnect
When reconnecting, the client sends its lastSyncTime to receive any changes that occurred while disconnected. The server maintains a change queue with:
- Maximum 1000 entries per project
- Maximum age of 5 minutes
- Per-query isolation
For disconnections longer than 5 minutes, clients receive fresh data without change replay.
Versioning
Each data message includes a version number. Clients can detect missed updates if versions are non-sequential:
{
"type": "data",
"id": "sub1",
"data": [...],
"meta": { "version": 42 }
}