Skip to content
Strata Sync

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 NameKey FieldsDescription
syncStart-A sync cycle has begun.
syncCompletelastSyncId: numberA sync cycle finished. lastSyncId is the highest sync ID received.
syncErrorerror: ErrorA sync cycle failed.
stateChangestate: SyncClientStateThe client transitioned to a new sync state.
connectionChangestate: ConnectionStateThe transport connection state changed.
outboxChangependingCount: numberThe count of unsynced transactions changed.
modelChangemodelName: string, modelId: string, action: ModelChangeActionA model was inserted, updated, deleted, archived, or unarchived (local or server).
rebaseConflictmodelName: string, modelId: string, conflictType: string, resolution: stringA 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

StateDescription
"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.