@crdt-sync/server 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @crdt-sync/server
|
|
2
|
+
|
|
3
|
+
A zero-dependency\* WebSocket relay server for the `crdt-sync` CRDT library.
|
|
4
|
+
|
|
5
|
+
> \*The only runtime dependency is the [`ws`](https://github.com/websockets/ws) library.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
The relay is intentionally simple — it maintains **no server-side state**. All CRDT merge logic runs inside the Wasm `StateStore` in each browser tab.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Client A ──► Relay ──broadcast──► Client B
|
|
13
|
+
└──broadcast──► Client C
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
When Client A writes to its CRDT store, the resulting **envelope** (a compact operation log entry) is sent to the relay as a JSON array. The relay broadcasts that array to every other connected client, which then applies the envelopes to their local Wasm stores.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @crdt-sync/server
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### CLI
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Start on the default port (8080)
|
|
30
|
+
npx crdt-sync-server
|
|
31
|
+
|
|
32
|
+
# Use a custom port
|
|
33
|
+
npx crdt-sync-server --port 3001
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Programmatic
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { createRelay } from '@crdt-sync/server';
|
|
40
|
+
|
|
41
|
+
const relay = createRelay({
|
|
42
|
+
port: 8080,
|
|
43
|
+
host: '0.0.0.0', // optional, default '0.0.0.0'
|
|
44
|
+
onListening: (port) => { // optional callback
|
|
45
|
+
console.log(`Relay ready on port ${port}`);
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Shut down gracefully
|
|
50
|
+
await relay.close();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Protocol
|
|
54
|
+
|
|
55
|
+
| Direction | Format | Description |
|
|
56
|
+
|-----------------|------------------------------------------|---------------------------------------------------|
|
|
57
|
+
| Client → Server | `JSON string of string[]` | Array of CRDT envelope JSON strings to broadcast |
|
|
58
|
+
| Server → Client | Same JSON string (forwarded as-is) | Sent to all clients **except** the sender |
|
|
59
|
+
|
|
60
|
+
### Example message
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
["{\"type\":\"lww\",\"key\":\"speed\",\"value\":100,\"ts\":1708801200000,\"nodeId\":\"client-abc123\"}"]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Self-hosting / Custom relay
|
|
67
|
+
|
|
68
|
+
You don't need this package to run the relay. Any WebSocket server that implements the protocol table above will work. Here's a minimal Node.js example using the `ws` library directly:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
72
|
+
|
|
73
|
+
const wss = new WebSocketServer({ port: 8080 });
|
|
74
|
+
|
|
75
|
+
wss.on('connection', (socket) => {
|
|
76
|
+
socket.on('message', (raw) => {
|
|
77
|
+
// Broadcast to all other clients
|
|
78
|
+
wss.clients.forEach((client) => {
|
|
79
|
+
if (client !== socket && client.readyState === WebSocket.OPEN) {
|
|
80
|
+
client.send(raw.toString());
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crdt-sync/server",
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "WebSocket relay server for crdt-sync",
|
|
5
|
+
"main": "dist/relay.js",
|
|
6
|
+
"types": "dist/relay.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"crdt-sync-server": "dist/relay.js"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/relay.d.ts",
|
|
13
|
+
"require": "./dist/relay.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup src/relay.ts --format cjs --dts --out-dir dist",
|
|
24
|
+
"start": "node dist/relay.js",
|
|
25
|
+
"dev": "ts-node src/relay.ts"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"ws": "^8.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/ws": "^8.0.0",
|
|
32
|
+
"ts-node": "^10.9.0",
|
|
33
|
+
"tsup": "^8.0.0",
|
|
34
|
+
"typescript": "^5.4.5"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT"
|
|
37
|
+
}
|