{"_id":"y-convex","_rev":"3-568a642ab17d5e711277a113f3c56269","name":"y-convex","dist-tags":{"latest":"1.0.1"},"versions":{"0.1.0":{"name":"y-convex","version":"0.1.0","keywords":["convex","component","y-convex"],"license":"Apache-2.0","_id":"y-convex@0.1.0","maintainers":[{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"}],"homepage":"https://github.com/nucleus48/y-convex#readme","bugs":{"url":"https://github.com/nucleus48/y-convex/issues"},"dist":{"shasum":"4c20d4c1f7a5b74decdf7e0aff7943ff1c3f44e7","tarball":"https://registry.npmjs.org/y-convex/-/y-convex-0.1.0.tgz","fileCount":57,"integrity":"sha512-HE/qz+IrL3hrwbNsEU5S+5ZlhXyiVzMW0fR6Y8Rnp5iFPNQNc6kIxiOo1gNx/NPiaaFsquWJrfeEPFF41jUf7A==","signatures":[{"sig":"MEUCIQCx3Er7Yuq0EiZ8MHdWSG+O4ngbhLnKCamcMd/1lmKf+QIgdRgoBP1EZ1+lWBVLYaOgyTM+680p6V5conqQHa1dDWQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":125321},"type":"module","_from":"file:y-convex-0.1.0.tgz","types":"./dist/client/index.d.ts","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"scripts":{"all":"run-p -r 'dev:*' 'test:watch'","dev":"run-p -r 'dev:*'","lint":"eslint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --project ./tsconfig.build.json","predev":"path-exists .env.local dist || (npm run build && convex dev --once)","release":"npm version patch && npm publish && git push --follow-tags","version":"vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && run-p test lint typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen","dev:backend":"convex dev --typecheck-components","dev:frontend":"cd example && vite --clearScreen false","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text"},"_npmUser":{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"},"_resolved":"/tmp/050df9e911a8dd0fedd6271a37301ac3/y-convex-0.1.0.tgz","_integrity":"sha512-HE/qz+IrL3hrwbNsEU5S+5ZlhXyiVzMW0fR6Y8Rnp5iFPNQNc6kIxiOo1gNx/NPiaaFsquWJrfeEPFF41jUf7A==","repository":{"url":"git+https://github.com/nucleus48/y-convex.git","type":"git"},"_npmVersion":"11.6.2","description":"Real-time, serverless Yjs synchronization for Convex. Persist and sync collaborative documents without managing WebSocket servers.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"yjs":"^13.6.29"},"_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.1","react":"^19.2.4","convex":"1.31.7","eslint":"9.39.2","vitest":"4.0.18","globals":"^17.3.0","prettier":"3.8.1","react-dom":"^19.2.4","@eslint/js":"9.39.2","pkg-pr-new":"^0.0.63","typescript":"5.9.3","@types/node":"^24.10.11","convex-test":"0.0.41","@types/react":"^19.2.13","chokidar-cli":"3.0.0","npm-run-all2":"8.0.4","path-exists-cli":"2.0.0","@edge-runtime/vm":"^5.0.0","@eslint/eslintrc":"^3.3.3","@types/react-dom":"^19.2.3","typescript-eslint":"8.54.0","eslint-plugin-react":"^7.37.5","@vitejs/plugin-react":"^5.1.3","@convex-dev/eslint-plugin":"^1.1.1","eslint-plugin-react-hooks":"^7.0.1","eslint-plugin-react-refresh":"^0.5.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.31.7"},"_npmOperationalInternal":{"tmp":"tmp/y-convex_0.1.0_1773097497960_0.2120989609388204","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"y-convex","version":"0.1.1","keywords":["convex","component","y-convex"],"license":"Apache-2.0","_id":"y-convex@0.1.1","maintainers":[{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"}],"homepage":"https://github.com/nucleus48/y-convex#readme","bugs":{"url":"https://github.com/nucleus48/y-convex/issues"},"dist":{"shasum":"ca38fb204b9cb6cd05102e3cdb0a65f9eeeedbc3","tarball":"https://registry.npmjs.org/y-convex/-/y-convex-0.1.1.tgz","fileCount":57,"integrity":"sha512-2wC1byca0g1yokDEmIZCdTvMs0+TD4j3HIchw2DAf6agPbnm/W7nrTRP10bIeqSEHnj0Kj942mdX6thLBwFbgQ==","signatures":[{"sig":"MEUCIQDDlK8Y1nm0dQ8FNF6pk3LStDuYLdwBmJwdH59/VFyBYAIgUGe+GtOjdzbnJhollBqHlPl24oAbzLo+pZp4iuv0TCM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":125299},"type":"module","_from":"file:y-convex-0.1.1.tgz","types":"./dist/client/index.d.ts","module":"./dist/client/index.js","exports":{".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./test":"./src/test.ts","./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./package.json":"./package.json","./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"}},"scripts":{"all":"run-p -r 'dev:*' 'test:watch'","dev":"run-p -r 'dev:*'","lint":"eslint .","test":"vitest run --typecheck","alpha":"npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags","build":"tsc --project ./tsconfig.build.json","predev":"path-exists .env.local dist || (npm run build && convex dev --once)","release":"npm version patch && npm publish && git push --follow-tags","version":"vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","preversion":"npm ci && npm run build:clean && run-p test lint typecheck","test:debug":"vitest --inspect-brk --no-file-parallelism","test:watch":"vitest --typecheck --clearScreen false","build:clean":"rm -rf dist *.tsbuildinfo && npm run build:codegen","dev:backend":"convex dev --typecheck-components","dev:frontend":"cd example && vite --clearScreen false","build:codegen":"npx convex codegen --component-dir ./src/component && npm run build","test:coverage":"vitest run --coverage --coverage.reporter=text"},"_npmUser":{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"},"_resolved":"/tmp/fd4187268d22f7cb41a5502e88cf4499/y-convex-0.1.1.tgz","_integrity":"sha512-2wC1byca0g1yokDEmIZCdTvMs0+TD4j3HIchw2DAf6agPbnm/W7nrTRP10bIeqSEHnj0Kj942mdX6thLBwFbgQ==","repository":{"url":"git+https://github.com/nucleus48/y-convex.git","type":"git"},"_npmVersion":"11.6.2","description":"Real-time, serverless Yjs synchronization for Convex. Persist and sync collaborative documents without managing WebSocket servers.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"yjs":"^13.6.29"},"_hasShrinkwrap":false,"devDependencies":{"vite":"7.3.1","react":"^19.2.4","convex":"1.31.7","eslint":"9.39.2","vitest":"4.0.18","globals":"^17.3.0","prettier":"3.8.1","react-dom":"^19.2.4","@eslint/js":"9.39.2","pkg-pr-new":"^0.0.63","typescript":"5.9.3","@types/node":"^24.10.11","convex-test":"0.0.41","@types/react":"^19.2.13","chokidar-cli":"3.0.0","npm-run-all2":"8.0.4","path-exists-cli":"2.0.0","@edge-runtime/vm":"^5.0.0","@eslint/eslintrc":"^3.3.3","@types/react-dom":"^19.2.3","typescript-eslint":"8.54.0","eslint-plugin-react":"^7.37.5","@vitejs/plugin-react":"^5.1.3","@convex-dev/eslint-plugin":"^1.1.1","eslint-plugin-react-hooks":"^7.0.1","eslint-plugin-react-refresh":"^0.5.0"},"peerDependencies":{"react":"^18.3.1 || ^19.0.0","convex":"^1.31.7"},"_npmOperationalInternal":{"tmp":"tmp/y-convex_0.1.1_1773152874033_0.6307441835032883","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"y-convex","version":"1.0.1","license":"ISC","type":"module","author":{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"},"homepage":"https://github.com/nucleus48/y-convex#readme","description":"Real-time, serverless Yjs synchronization for Convex. Persist and sync collaborative documents without managing WebSocket servers.","repository":{"type":"git","url":"git+https://github.com/nucleus48/y-convex.git"},"bugs":{"url":"https://github.com/nucleus48/y-convex/issues","email":"nucleuserumagborie@gmail.com"},"keywords":["convex","yjs","crdt","collaborative-editing","react","serverless","real-time-sync","snapshotting","component","y-convex"],"scripts":{"dev":"run-p -r 'dev:*'","dev:backend":"convex dev --typecheck-components","dev:frontend":"cd example && vite --clearScreen false","dev:build":"chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'pnpm build:codegen' --initial","predev":"path-exists .env.local dist || (pnpm build && pnpm convex dev --once)","build":"tsc --project ./tsconfig.build.json","build:codegen":"pnpm convex codegen --component-dir ./src/component && pnpm build","build:clean":"rm -rf dist *.tsbuildinfo && pnpm build:codegen","typecheck":"tsc --noEmit && tsc -p example && tsc -p example/convex","lint":"eslint .","all":"run-p -r 'dev:*' 'test:watch'","test":"vitest run --typecheck","test:watch":"vitest --typecheck --clearScreen false","test:debug":"vitest --inspect-brk --no-file-parallelism","test:coverage":"vitest run --coverage --coverage.reporter=text"},"exports":{"./package.json":"./package.json",".":{"types":"./dist/client/index.d.ts","default":"./dist/client/index.js"},"./react":{"types":"./dist/react/index.d.ts","default":"./dist/react/index.js"},"./_generated/component.js":{"types":"./dist/component/_generated/component.d.ts"},"./_generated/component":{"types":"./dist/component/_generated/component.d.ts"},"./convex.config.js":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"},"./convex.config":{"types":"./dist/component/convex.config.d.ts","default":"./dist/component/convex.config.js"}},"peerDependencies":{"convex":"^1.31.7","react":"^18.3.1 || ^19.0.0"},"devDependencies":{"@convex-dev/eslint-plugin":"^1.1.1","@edge-runtime/vm":"^5.0.0","@eslint/eslintrc":"^3.3.3","@eslint/js":"9.39.2","@types/node":"^24.10.11","@types/react":"^19.2.13","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^5.1.3","chokidar-cli":"3.0.0","convex":"1.31.7","convex-test":"0.0.41","eslint":"9.39.2","eslint-plugin-react":"^7.37.5","eslint-plugin-react-hooks":"^7.0.1","eslint-plugin-react-refresh":"^0.5.0","globals":"^17.3.0","npm-run-all2":"8.0.4","path-exists-cli":"2.0.0","pkg-pr-new":"^0.0.63","prettier":"3.8.1","react":"^19.2.4","react-dom":"^19.2.4","typescript":"5.9.3","typescript-eslint":"8.54.0","vite":"7.3.1","vitest":"4.0.18"},"types":"./dist/client/index.d.ts","module":"./dist/client/index.js","pnpm":{"onlyBuiltDependencies":["esbuild","@tailwindcss/oxide"]},"dependencies":{"yjs":"^13.6.29"},"release":{"branches":["main"],"plugins":["@semantic-release/commit-analyzer","@semantic-release/release-notes-generator","@semantic-release/changelog","@semantic-release/npm","@semantic-release/github",["@semantic-release/git",{"assets":["package.json","CHANGELOG.md"],"message":"chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"}]]},"gitHead":"55272dc332c814eddad1c76064dbfc3c31dbc3ce","_id":"y-convex@1.0.1","_nodeVersion":"24.14.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-ZM54rTSB7qVCOUbHHjsUYZAcHKgewJDcBXs9AG8rSdXQfB2Y7RqijFjB5R2oiYQJh9sZYR7RSTJHLlpnJzTQNw==","shasum":"cff65197179f3eef1fec1db3ba42c323f6c2002a","tarball":"https://registry.npmjs.org/y-convex/-/y-convex-1.0.1.tgz","fileCount":53,"unpackedSize":73057,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/y-convex@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDdligXgQmpPkzl1TGgnXiYqhUu6FjbdeeS9xPeS+YuuQIgBdWxl8ntPrhHfAiBrVFoeVP2ZlcT7qQiWlp1kHq+92g="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:9711a5de-c750-43c1-8a86-e9764a8cece4"}},"directories":{},"maintainers":[{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/y-convex_1.0.1_1773194027382_0.6220176836597235"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-09T23:04:57.845Z","modified":"2026-03-11T01:53:47.822Z","0.1.0":"2026-03-09T23:04:58.119Z","0.1.1":"2026-03-10T14:27:54.181Z","1.0.1":"2026-03-11T01:53:47.539Z"},"bugs":{"url":"https://github.com/nucleus48/y-convex/issues","email":"nucleuserumagborie@gmail.com"},"license":"ISC","homepage":"https://github.com/nucleus48/y-convex#readme","keywords":["convex","yjs","crdt","collaborative-editing","react","serverless","real-time-sync","snapshotting","component","y-convex"],"repository":{"type":"git","url":"git+https://github.com/nucleus48/y-convex.git"},"description":"Real-time, serverless Yjs synchronization for Convex. Persist and sync collaborative documents without managing WebSocket servers.","maintainers":[{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"}],"readme":"# y-convex\n\n[![npm version](https://img.shields.io/npm/v/y-convex.svg)](https://www.npmjs.com/package/y-convex)\n[![License](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)\n[![Convex](https://img.shields.io/badge/Convex-Backend-EE714B.svg)](https://convex.dev)\n[![Yjs](https://img.shields.io/badge/Yjs-CRDT-blue.svg)](https://docs.yjs.dev/)\n[![React](https://img.shields.io/badge/React-Hooks-61DAFB.svg)](https://react.dev)\n[![Typescript](https://img.shields.io/badge/Typescript-Ready-3178C6.svg)](https://www.typescriptlang.org/)\n\n**Real-time Yjs synchronization for Convex.**\n\n## Why Y-Convex?\n\nMost Yjs providers rely on WebSockets (like `y-websocket`). While effective,\nthey require maintaining a separate server or serverless fleet. `y-convex`\noffers several advantages:\n\n- **Serverless**: No WebSocket servers to manage. All sync logic runs as Convex\n  functions.\n- **Transactional**: Updates are stored with Convex's ACID guarantees, ensuring\n  document integrity.\n- **Unified Backend**: Keep your collaborative state alongside your other\n  application data in Convex.\n- **Reactive**: Leverages Convex's built-in reactivity to broadcast changes to\n  all clients instantly.\n\n## Features\n\n- 🚀 **Real-time Sync**: Collaborative editing with zero-latency feeling using\n  Convex's reactive engine.\n- 💾 **Persistent Storage**: Changes are automatically persisted to Convex.\n- 📸 **Automatic Snapshotting**: Automatically compresses document history into\n  snapshots to keep database queries fast and storage efficient.\n- ⚛️ **React-First**: Includes a drop-in React hook for easy integration.\n- 🔒 **Conflict-Free**: Leverages Yjs's CRDT (Conflict-free Replicated Data\n  Type) logic for reliable state merging.\n\n## Installation\n\n```sh\npnpm add y-convex yjs\n```\n\n## Quick Start\n\n### 1. Register the component\n\nCreate a `convex/convex.config.ts` file (or update your existing one) to include\nthe `y-convex` component:\n\n```ts\n// convex/convex.config.ts\nimport { defineApp } from \"convex/server\";\nimport yconvex from \"y-convex/convex.config\";\n\nconst app = defineApp();\napp.use(yconvex);\n\nexport default app;\n```\n\n### 2. Expose the API\n\nCreate a file named `convex/yconvex.ts` to expose the component's functionality\nto your application:\n\n```ts\n// convex/yconvex.ts\nimport { exposeApi } from \"y-convex\";\nimport { components } from \"./_generated/api\";\n\nexport const { init, push, pull } = exposeApi(components.yconvex);\n```\n\n### 3. Use in your React app\n\nNow you can use the `useYConvexSync` hook to synchronize a Yjs `Doc` with\nConvex:\n\n```tsx\nimport { useMemo } from \"react\";\nimport * as Y from \"yjs\";\nimport { useYConvexSync } from \"y-convex/react\";\nimport { api } from \"../convex/_generated/api\";\n\nexport default function CollaborativeEditor({ docId }) {\n  // 1. Initialize a Y.Doc\n  const doc = useMemo(() => new Y.Doc(), []);\n\n  // 2. Sync it with Convex\n  // Note: api.yconvex refers to the file created in step 2\n  useYConvexSync(api.yconvex, docId, doc);\n\n  // 3. Use standard Yjs patterns\n  const yText = doc.getText(\"content\");\n\n  // ... rest of your editor logic\n}\n```\n\n## How It Works\n\n### The Sync Loop\n\n1. **Initialization**: When the hook mounts, it calls `init` to fetch the\n   current server state vector and merged updates.\n2. **Pushing Changes**: Local updates on the `Y.Doc` are caught via the `update`\n   event and pushed to Convex using a `push` mutation.\n3. **Pulling Changes**: The hook subscribes to a `pull` query that reactively\n   provides new updates from other clients.\n\n### Snapshotting\n\n`y-convex` includes a built-in snapshotting mechanism. When the number of\nincremental updates for a document exceeds a threshold (default 100), the\ncomponent automatically:\n\n1. Merges all existing updates and snapshots into a single block.\n2. Uploads this merged state to Convex File Storage.\n3. Cleans up the old incremental updates from the database.\n\nThis ensures that the initial load time remains fast even for long-lived\ndocuments with thousands of edits.\n\n## API Reference\n\n### Backend API (`y-convex`)\n\n#### `exposeApi(component)`\n\nUsed in your `convex/` directory to re-export the component's functions.\n\n### Frontend API (`y-convex/react`)\n\n#### `useYConvexSync(api, docId, doc)`\n\nA React hook to synchronize a Yjs doc.\n\n- `api`: The API object containing `init`, `push`, and `pull` (created via\n  `exposeApi`).\n- `docId`: A string identifying the document.\n- `doc`: The `Y.Doc` instance to sync.\n\n## Developing and Running Examples\n\nThe repository includes an example project to help you get started or test\nchanges.\n\n1.  **Clone and Install**:\n\n    ```sh\n    git clone https://github.com/nucleus48/y-convex.git\n    cd y-convex\n    pnpm install\n    ```\n\n2.  **Run Development Mode**:\n    ```sh\n    pnpm dev\n    ```\n    This will start the Convex backend and a Vite frontend for the example app.\n\n## License\n\nISC\n","readmeFilename":"README.md","author":{"name":"nucleus48","email":"nucleuserumagborie@gmail.com"}}