{"_id":"@ahmetskilinc/sync-react","name":"@ahmetskilinc/sync-react","dist-tags":{"latest":"0.4.0"},"versions":{"0.4.0":{"name":"@ahmetskilinc/sync-react","version":"0.4.0","description":"React bindings for sync-engine: live queries, index reads, status and rejection surfaces over the local-first client","license":"MIT","type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"keywords":["sync","realtime","local-first","offline-first","optimistic-ui","react"],"scripts":{"build":"tsc -b","prepublishOnly":"bunx tsc -b"},"dependencies":{"@ahmetskilinc/sync-core":"^0.4.0","@ahmetskilinc/sync-client":"^0.4.0"},"peerDependencies":{"react":">=18"},"devDependencies":{"react":"^19.2.4","react-dom":"^19.2.4","@types/react":"^19","@types/react-dom":"^19"},"repository":{"type":"git","url":"git+https://github.com/ahmetskilinc/sync-engine.git","directory":"packages/react"},"publishConfig":{"access":"public"},"engines":{"node":">=18"},"homepage":"https://github.com/ahmetskilinc/sync-engine#readme","bugs":{"url":"https://github.com/ahmetskilinc/sync-engine/issues"},"author":{"name":"Ahmet Kilinc"},"gitHead":"1bb2539de11edec64b930ee0cb1d362aca50d201","_id":"@ahmetskilinc/sync-react@0.4.0","_nodeVersion":"24.19.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-KQDKkQVpe9Y/6HHmzh8pGT/hdY9GifC3u2fTCZdNoNPCJ6Z3l209EGV8IE3cD1XtmeShau/AsCZNwh8WjVnh5A==","shasum":"bef708bf65765b215d6d6458b7e95da959c8b4d9","tarball":"https://registry.npmjs.org/@ahmetskilinc/sync-react/-/sync-react-0.4.0.tgz","fileCount":23,"unpackedSize":50321,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGMxjbcex2ficR7BzXfiUrhcLIx15fdeuS74IExawdYEAiEAnI/vtT7qe8AHVXRkUs623SrnNER8NWfWKzXq2N1zdh0="}]},"_npmUser":{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"},"directories":{},"maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sync-react_0.4.0_1787933675021_0.4698764575543437"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-28T16:14:34.821Z","0.4.0":"2026-08-28T16:14:35.159Z","modified":"2026-08-28T16:14:35.362Z"},"maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"description":"React bindings for sync-engine: live queries, index reads, status and rejection surfaces over the local-first client","homepage":"https://github.com/ahmetskilinc/sync-engine#readme","keywords":["sync","realtime","local-first","offline-first","optimistic-ui","react"],"repository":{"type":"git","url":"git+https://github.com/ahmetskilinc/sync-engine.git","directory":"packages/react"},"author":{"name":"Ahmet Kilinc"},"bugs":{"url":"https://github.com/ahmetskilinc/sync-engine/issues"},"license":"MIT","readme":"# @ahmetskilinc/sync-react\n\nReact bindings for [sync-engine](https://github.com/ahmetskilinc/sync-engine):\nlive queries, index reads, and status/rejection surfaces over the local-first\nclient — with the identity-stability details (`useSyncExternalStore` snapshot\ncaching, per-model wake-ups, per-group index subscriptions) done once, here,\ninstead of in every app.\n\n```bash\nnpm install @ahmetskilinc/sync-react @ahmetskilinc/sync-client @ahmetskilinc/sync-core\n```\n\n## Setup\n\n```tsx\nimport { SyncProvider } from \"@ahmetskilinc/sync-react\";\nimport { IndexedDBPersistence, SyncClient, WebSocketTransport } from \"@ahmetskilinc/sync-client\";\nimport { schema, Thread } from \"./schema\";\n\nfunction createClient() {\n  const client = new SyncClient({\n    schema,\n    transport: new WebSocketTransport(\"wss://app.example.com/api/sync\"),\n    persistence: new IndexedDBPersistence(`app-${userId}`),\n    scope: userId,\n  });\n  // Define store indexes here, right after construction.\n  client.store.defineIndex(Thread, {\n    name: \"inbox\",\n    key: (t) => (t.archived ? null : t.folderId),\n    compare: (a, b) => b.updatedAt.localeCompare(a.updatedAt),\n  });\n  return client;\n}\n\n<SyncProvider createClient={createClient}>\n  <App />\n</SyncProvider>;\n```\n\n`createClient` is called lazily, in the browser only — server rendering gets\nempty snapshots and never constructs a client.\n\n## Hooks\n\n| Hook | Returns |\n| --- | --- |\n| `useQuery(model, selector?, deps?)` | Live records, selector applied outside the subscription |\n| `useRecord(model, id)` | One record, identity-stable |\n| `useIndex(model, name, key, { limit, offset })` | One ordered index group; subscribes to that group only |\n| `useSyncStatus()` | `\"offline\" \\| \"connecting\" \\| \"syncing\" \\| \"online\"` |\n| `useHydrated()` | True once persisted state has loaded — gate skeletons on this |\n| `useHasPendingChanges()` | True while local writes await confirmation |\n| `useRejections()` | Queue of server rejections + `dismiss(transactionId)` |\n| `usePull(name, args, { enabled })` | Effect-driven named pull with in-flight dedup |\n| `useSyncClient()` | The `SyncClient`, for mutations from event handlers |\n\nAll packages move in lockstep — see the repo's MIGRATION.md.\n","readmeFilename":"README.md","_rev":"1-a4b83a6912ec074a77cb3dff5292eff6"}