AI agents: fetch the documentation index at llms.txt. Markdown versions are available by appending .md to any page URL, including this page's markdown.
Event system
Subscribe to sync lifecycle events for state management and UI updates.
Subscribe to typed events for UI updates, notifications, or side effects.
Subscribing to events
Use onEvent to listen to all event types. It returns an unsubscribe function.
const unsubscribe = client.onEvent((event) => {
switch (event.type) {
case "syncStart":
console.log("Sync started");
break;
case "syncComplete":
console.log("Synced to ID:", event.lastSyncId);
break;
case "syncError":
console.error("Sync error:", event.error);
break;
case "modelChange":
console.log(`${event.action} ${event.modelName}:${event.modelId}`);
break;
}
});
// Clean up when done
unsubscribe();Specialized subscribers
Convenience methods for narrower subscriptions:
onStateChange
Subscribe to sync state transitions only.
const unsubscribe = client.onStateChange((state) => {
console.log("New state:", state);
// "disconnected" | "connecting" | "bootstrapping" | "syncing" | "error"
});onConnectionStateChange
Subscribe to connection state transitions only.
const unsubscribe = client.onConnectionStateChange((state) => {
console.log("Connection:", state);
});Event types
Every event has a type discriminant.
| Event Name | Key Fields | Description |
|---|---|---|
syncStart | - | A sync cycle has begun. |
syncComplete | lastSyncId: number | A sync cycle finished. lastSyncId is the highest sync ID received. |
syncError | error: Error | A sync cycle failed. |
stateChange | state: SyncClientState | The client transitioned to a new sync state. |
connectionChange | state: ConnectionState | The transport connection state changed. |
outboxChange | pendingCount: number | The count of unsynced transactions changed. |
modelChange | modelName: string, modelId: string, action: ModelChangeAction | A model was inserted, updated, deleted, archived, or unarchived (local or server). |
rebaseConflict | modelName: string, modelId: string, conflictType: string, resolution: string | A conflict was detected during transaction rebasing. |
// Full type definitions
type SyncEvent =
| { type: "syncStart" }
| { type: "syncComplete"; lastSyncId: number }
| { type: "syncError"; error: Error }
| { type: "stateChange"; state: SyncClientState }
| { type: "connectionChange"; state: ConnectionState }
| { type: "outboxChange"; pendingCount: number }
| {
type: "modelChange";
modelName: string;
modelId: string;
action: ModelChangeAction;
}
| {
type: "rebaseConflict";
modelName: string;
modelId: string;
conflictType: string;
resolution: string;
};
type ModelChangeAction =
| "insert"
| "update"
| "delete"
| "archive"
| "unarchive";SyncClientState values
| State | Description |
|---|---|
"disconnected" | Not connected to the server. |
"connecting" | Establishing a connection. |
"bootstrapping" | Loading initial data from the server. |
"syncing" | Connected and syncing deltas. This is the "ready" state. |
"error" | An unrecoverable error occurred. |
Usage with React
In React, use the hooks from @stratasync/react instead of calling onEvent directly.
import { useConnectionState, usePendingCount } from "@stratasync/react";
function SyncStatus() {
const { status, lastSyncId, error } = useConnectionState();
const { count, hasPending } = usePendingCount();
return (
<div>
<span>Status: {status}</span>
<span>Sync ID: {lastSyncId}</span>
{hasPending && <span>{count} pending</span>}
{error && <span>Error: {error.message}</span>}
</div>
);
}See Offline-first patterns for a complete sync status indicator example.