@ahmetskilinc/sync-react
v0.4.0
Published
React bindings for sync-engine: live queries, index reads, status and rejection surfaces over the local-first client
Maintainers
Readme
@ahmetskilinc/sync-react
React bindings for sync-engine:
live queries, index reads, and status/rejection surfaces over the local-first
client — with the identity-stability details (useSyncExternalStore snapshot
caching, per-model wake-ups, per-group index subscriptions) done once, here,
instead of in every app.
npm install @ahmetskilinc/sync-react @ahmetskilinc/sync-client @ahmetskilinc/sync-coreSetup
import { SyncProvider } from "@ahmetskilinc/sync-react";
import { IndexedDBPersistence, SyncClient, WebSocketTransport } from "@ahmetskilinc/sync-client";
import { schema, Thread } from "./schema";
function createClient() {
const client = new SyncClient({
schema,
transport: new WebSocketTransport("wss://app.example.com/api/sync"),
persistence: new IndexedDBPersistence(`app-${userId}`),
scope: userId,
});
// Define store indexes here, right after construction.
client.store.defineIndex(Thread, {
name: "inbox",
key: (t) => (t.archived ? null : t.folderId),
compare: (a, b) => b.updatedAt.localeCompare(a.updatedAt),
});
return client;
}
<SyncProvider createClient={createClient}>
<App />
</SyncProvider>;createClient is called lazily, in the browser only — server rendering gets
empty snapshots and never constructs a client.
Hooks
| Hook | Returns |
| --- | --- |
| useQuery(model, selector?, deps?) | Live records, selector applied outside the subscription |
| useRecord(model, id) | One record, identity-stable |
| useIndex(model, name, key, { limit, offset }) | One ordered index group; subscribes to that group only |
| useSyncStatus() | "offline" \| "connecting" \| "syncing" \| "online" |
| useHydrated() | True once persisted state has loaded — gate skeletons on this |
| useHasPendingChanges() | True while local writes await confirmation |
| useRejections() | Queue of server rejections + dismiss(transactionId) |
| usePull(name, args, { enabled }) | Effect-driven named pull with in-flight dedup |
| useSyncClient() | The SyncClient, for mutations from event handlers |
All packages move in lockstep — see the repo's MIGRATION.md.
