{"_id":"@ahmetskilinc/sync-server","_rev":"5-999c40df940391de09f42edf30738b9f","name":"@ahmetskilinc/sync-server","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@ahmetskilinc/sync-server","version":"0.1.0","keywords":["sync","realtime","local-first","websocket","sync-log"],"license":"MIT","_id":"@ahmetskilinc/sync-server@0.1.0","maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"homepage":"https://github.com/ahmetskilinc/sync-engine#readme","bugs":{"url":"https://github.com/ahmetskilinc/sync-engine/issues"},"dist":{"shasum":"a732fccd6a0b4245e73f70b86aef674ee9886286","tarball":"https://registry.npmjs.org/@ahmetskilinc/sync-server/-/sync-server-0.1.0.tgz","fileCount":21,"integrity":"sha512-7eV9epBQFwItYNNt87nzFhBFkst4kKiGbhvHqrEvkjOG88jbrT8sjPYNKVn7qfObPKQdNur+pvPIcU5Op54YzA==","signatures":[{"sig":"MEYCIQCKY60260KHpuXKIz+IzTbJglnIBQ+WbHKkERuVSwYKkwIhAM3njgibqbxGAslOQINtMznLnvwVjGHtcBhfzd9iu8cP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40253},"main":"./dist/index.js","type":"module","_from":"file:packages/server/ahmetskilinc-sync-server-0.1.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -b","prepublishOnly":"bunx tsc -b"},"_npmUser":{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"},"_resolved":"/Users/ahmetkilinc/Developer/sync-engine/packages/server/ahmetskilinc-sync-server-0.1.0.tgz","_integrity":"sha512-7eV9epBQFwItYNNt87nzFhBFkst4kKiGbhvHqrEvkjOG88jbrT8sjPYNKVn7qfObPKQdNur+pvPIcU5Op54YzA==","repository":{"url":"git+https://github.com/ahmetskilinc/sync-engine.git","type":"git","directory":"packages/server"},"_npmVersion":"11.6.2","description":"Server for sync-engine: source-of-truth apply loop, global sync-ID log, WebSocket fan-out","directories":{},"sideEffects":false,"_nodeVersion":"24.12.0","dependencies":{"@ahmetskilinc/sync-core":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sync-server_0.1.0_1785253957758_0.7298839984695091","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ahmetskilinc/sync-server","version":"0.2.0","keywords":["sync","realtime","local-first","websocket","sync-log"],"license":"MIT","_id":"@ahmetskilinc/sync-server@0.2.0","maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"dist":{"shasum":"56d9a045161783d55e862b307051ca9155b17b13","tarball":"https://registry.npmjs.org/@ahmetskilinc/sync-server/-/sync-server-0.2.0.tgz","fileCount":21,"integrity":"sha512-GhzV0DcqVLTeZmoc7obGdpdAUY+kCO7VtYaIpTzgPs8WB70MYGzI7/EZVydOSLdUOOdJ6U1rWSlKrNsVF0G04w==","signatures":[{"sig":"MEYCIQDuj00nL33v6hgiWzTdECaSrfnqkvJpHIRxUfGOfGS6yAIhAKN2eGN8jiYJCzDrMJPD82kzQwQmtg2MIadcWcUV0TZp","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42375},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","shasum":"56d9a045161783d55e862b307051ca9155b17b13","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -b","prepublishOnly":"bunx tsc -b"},"_npmUser":{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"},"_integrity":"sha512-GhzV0DcqVLTeZmoc7obGdpdAUY+kCO7VtYaIpTzgPs8WB70MYGzI7/EZVydOSLdUOOdJ6U1rWSlKrNsVF0G04w==","repository":{"url":"git+https://github.com/ahmetskilinc/sync-engine.git","type":"git","directory":"packages/server"},"_npmVersion":"10.8.3","description":"Server for sync-engine: source-of-truth apply loop, global sync-ID log, WebSocket fan-out","directories":{},"sideEffects":false,"_nodeVersion":"24.3.0","dependencies":{"@ahmetskilinc/sync-core":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sync-server_0.2.0_1785257754568_0.497872287093615","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@ahmetskilinc/sync-server","version":"0.2.1","keywords":["sync","realtime","local-first","websocket","sync-log"],"license":"MIT","_id":"@ahmetskilinc/sync-server@0.2.1","maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"dist":{"shasum":"33d1efdd5054c7e7a7fc5eda12a10f79a0907bed","tarball":"https://registry.npmjs.org/@ahmetskilinc/sync-server/-/sync-server-0.2.1.tgz","fileCount":21,"integrity":"sha512-RDZ6A8SgPUqzhQ0wM9YclA5ehYj4N2ifOgAFroukpvVySX+JI3msQrSezhKaUYWhtxf2NUm3xSLY/KybZ3Zd8A==","signatures":[{"sig":"MEQCIHoaO1ks2kEyoVvYkljvWR3Iwnlm+agJmUeGZzI3zD2VAiAIv/39Z8tM1LjQaDikxIM4EcstebE9V5dJn7Db0Q8cIQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":42376},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","shasum":"33d1efdd5054c7e7a7fc5eda12a10f79a0907bed","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -b","prepublishOnly":"bunx tsc -b"},"_npmUser":{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"},"_integrity":"sha512-RDZ6A8SgPUqzhQ0wM9YclA5ehYj4N2ifOgAFroukpvVySX+JI3msQrSezhKaUYWhtxf2NUm3xSLY/KybZ3Zd8A==","repository":{"url":"git+https://github.com/ahmetskilinc/sync-engine.git","type":"git","directory":"packages/server"},"_npmVersion":"10.8.3","description":"Server for sync-engine: source-of-truth apply loop, global sync-ID log, WebSocket fan-out","directories":{},"sideEffects":false,"_nodeVersion":"24.3.0","dependencies":{"@ahmetskilinc/sync-core":"^0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sync-server_0.2.1_1785258628529_0.7753645852627433","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ahmetskilinc/sync-server","version":"0.3.0","keywords":["sync","realtime","local-first","websocket","sync-log"],"author":{"name":"Ahmet Kilinc"},"license":"MIT","_id":"@ahmetskilinc/sync-server@0.3.0","maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"homepage":"https://github.com/ahmetskilinc/sync-engine#readme","bugs":{"url":"https://github.com/ahmetskilinc/sync-engine/issues"},"dist":{"shasum":"1b236c53919042e20023065acaecb2527634bb88","tarball":"https://registry.npmjs.org/@ahmetskilinc/sync-server/-/sync-server-0.3.0.tgz","fileCount":33,"integrity":"sha512-Chf971Ew9biOjMfunAqQJyK91JAvzQvOgqhkDTQfkKYpw3pjo7e1y2RyC7HYfnUS1UsKbZa/kvT6VddrZeTshw==","signatures":[{"sig":"MEUCIQCLIIILl3BUO/+5R1dzVeUpiFASybM4Cxneuv0HZYRkYwIgI8HSWLD/LPBMUx7nxcTacoDCu5r+9AvJmK8XiSM9RPk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170260},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"731047322ef77a734afac45762fbc4ed735a0bad","scripts":{"build":"tsc -b","prepublishOnly":"bunx tsc -b"},"_npmUser":{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"},"repository":{"url":"git+https://github.com/ahmetskilinc/sync-engine.git","type":"git","directory":"packages/server"},"_npmVersion":"11.6.2","description":"Server for sync-engine: source-of-truth apply loop, global sync-ID log, WebSocket fan-out","directories":{},"sideEffects":false,"_nodeVersion":"24.12.0","dependencies":{"@ahmetskilinc/sync-core":"^0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/sync-server_0.3.0_1785598991588_0.1510230880626422","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ahmetskilinc/sync-server","version":"0.4.0","description":"Server for sync-engine: source-of-truth apply loop, global sync-ID log, WebSocket fan-out","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","websocket","sync-log"],"scripts":{"build":"tsc -b","prepublishOnly":"bunx tsc -b"},"dependencies":{"@ahmetskilinc/sync-core":"^0.4.0"},"repository":{"type":"git","url":"git+https://github.com/ahmetskilinc/sync-engine.git","directory":"packages/server"},"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-server@0.4.0","_nodeVersion":"24.19.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-1UVUot+f9MCLWIIiHAmneGwhY+q6vRpULepn8lmUXChIDk3798klBjaJBjiC+aktJP8WwtFfGAEOnLJiGgT1ag==","shasum":"0cf79cf8f2c99a7d68899a16d6c192d9a0d7f8d4","tarball":"https://registry.npmjs.org/@ahmetskilinc/sync-server/-/sync-server-0.4.0.tgz","fileCount":38,"unpackedSize":219019,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAX9QlueO9dtVKZCW3LoIz2GK+ngSt4fbuzZt44uku5BAiEA56s4eeGLkQ2z8t03lGIHBhMJrQC9w5v6z+MaYqq63aE="}]},"_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-server_0.4.0_1787933672949_0.1540640280913479"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-28T15:52:37.565Z","modified":"2026-08-28T16:14:33.298Z","0.1.0":"2026-07-28T15:52:37.936Z","0.2.0":"2026-07-28T16:55:54.718Z","0.2.1":"2026-07-28T17:10:28.674Z","0.3.0":"2026-08-01T15:43:11.795Z","0.4.0":"2026-08-28T16:14:33.106Z"},"bugs":{"url":"https://github.com/ahmetskilinc/sync-engine/issues"},"author":{"name":"Ahmet Kilinc"},"license":"MIT","homepage":"https://github.com/ahmetskilinc/sync-engine#readme","keywords":["sync","realtime","local-first","websocket","sync-log"],"repository":{"type":"git","url":"git+https://github.com/ahmetskilinc/sync-engine.git","directory":"packages/server"},"description":"Server for sync-engine: source-of-truth apply loop, global sync-ID log, WebSocket fan-out","maintainers":[{"name":"ahmetskilinc","email":"ahmetskilinc@icloud.com"}],"readme":"# @ahmetskilinc/sync-server\n\nThe server half of [sync-engine](https://github.com/ahmetskilinc/sync-engine): applies client transactions to your database, stamps each confirmed mutation with a global sync ID, and fans it out to every connected client.\n\n```bash\nnpm install @ahmetskilinc/sync-server @ahmetskilinc/sync-core\n```\n\n```ts\nimport { WebSocketServer } from \"ws\";\nimport {\n  SyncServer,\n  attachWebSocketGuarded,\n  createConnectionGuard,\n  getCookie,\n} from \"@ahmetskilinc/sync-server\";\nimport { schema } from \"./schema.js\";\n\nconst server = new SyncServer({\n  schema,\n  database: new MyPostgresAdapter(),   // MemoryDatabase by default\n  requireContext: true,\n  validateTransaction: (txn, context) => null,          // write rules\n  authorizeRead: (record, model, context) =>            // read rules\n    record.tenantId === context.tenantId,\n  onError: (error, where) => logger.error({ error, where }),\n});\n\nconst guard = createConnectionGuard({\n  origin: [\"https://app.example.com\"],\n  authenticate: async (request) => {\n    const token = getCookie(request, \"session\");\n    return token ? await lookupUser(token) : null;      // null ⇒ refuse\n  },\n});\n\nconst wss = new WebSocketServer({ port: 8080, maxPayload: 256 * 1024 });\nwss.on(\"connection\", (socket, request) => {\n  void attachWebSocketGuarded(server, socket, request, guard);\n});\n```\n\n## Security defaults worth understanding\n\n**Browsers do not apply the same-origin policy to WebSockets.** Any page on any origin can open a socket to your server, and the browser attaches the user's cookies. Authenticating from a cookie without checking `Origin` means every logged-in user is one visited page away from a full session (cross-site WebSocket hijacking). `createConnectionGuard` checks `Origin` by default and refuses requests carrying none.\n\n`authorizeRead` governs what a connection may *see* — applied to the bootstrap snapshot, catch-up, and live fan-out. Without it, every client receives every record, even with perfect authentication.\n\nPair both with `requireContext: true`, so a connection that somehow skipped the guard cannot write.\n\n## Persistence\n\nImplement `DatabaseAdapter`: `get`, `put`, `delete`, `getAll`, plus an optional but strongly recommended `applyBatch` that commits one transaction's writes atomically. Without `applyBatch`, a failure partway through leaves earlier writes committed while the client rolls everything back — the database and sync log then disagree permanently.\n\n## Deployment\n\nSingle long-lived process by default. For serverless or multi-instance, pass `distributed` (shared sync-ID sequence + action table) and a stable `epoch`, and feed `ingestActions` from that table.\n\n`server.stats` reports connections, queue depth, log size and pending acks for monitoring; `maxConnections` bounds fan-out cost.\n\nZero runtime dependencies beyond `@ahmetskilinc/sync-core` — the WebSocket type is structural, so `ws` is not required.\n\n---\n\nFull documentation: [github.com/ahmetskilinc/sync-engine](https://github.com/ahmetskilinc/sync-engine) · Upgrading? See [MIGRATION.md](https://github.com/ahmetskilinc/sync-engine/blob/main/MIGRATION.md)\n\nMIT\n","readmeFilename":"README.md"}