@automerge/automerge-repo-network-websocket 1.0.12 → 1.0.15

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 CHANGED
@@ -3,3 +3,195 @@
3
3
  Includes two implementations, a Websocket client and a Websocket server. These are used by the example sync-server.
4
4
 
5
5
  The package uses isomorphic-ws to share code between node and the browser, but the server code is node only due to lack of browser support.
6
+
7
+ ## Wire Protocol
8
+
9
+ ### Peer naming
10
+
11
+ Whilst currently this wire protocol is only used for the websocket, it is
12
+ probably generically useful for any stream oriented transport (e.g. TCP or
13
+ QUIC). To make translating this spec to other transports easier we refer to the
14
+ two parties in the protocol as the "initiating" and "receiving" peers. In the
15
+ WebSocket case the "initiating" peer is the client and the "receiving" peer
16
+ is the server.
17
+
18
+ ### Overview
19
+
20
+ The websocket wire protocol consists of a handshake where each peer tells the
21
+ other what their peer ID is followed by the sync loop where each peer can send
22
+ the other sync messages and ephemeral messages.
23
+
24
+ ### Handshake
25
+
26
+ Before sync can continue each peer needs to exchange peer IDs and agree on the
27
+ protocol version they are using (although currently there is only one version).
28
+ Handshake is the following steps:
29
+
30
+ * Once a connection is established the initiating peer sends a
31
+ [join](#join) message with the `senderId` set to the initiating peers ID and
32
+ the `protocolVersion` set to "1"
33
+ * The receiving peer waits until it receives a message from the initiating
34
+ peer, if the initiating peer receives a message before sending the join message
35
+ the initiating peer SHOULD terminate the connection.
36
+ * When the receiving peer receives the join message
37
+ * if the `protocolVersion` is not "1" the receiving peer sends an
38
+ [error](#error) message and terminates the connection
39
+ * otherwise
40
+ * store the `senderId` as the peer ID of the initiating peer
41
+ * emit a "peer-candidate" event with the sender ID as the peer
42
+ * respond with a [peer](#peer) message with the `targetId` set to the
43
+ initiating peers peer ID, the `senderId` set to the receiving peers
44
+ peer ID and the `selectedProtocolVersion` set to "1"
45
+ * begin the sync phase
46
+ * Once the initiating peer has sent the join message it waits for a peer message
47
+ in response. If it receives any other message type before the join message
48
+ the receiving peer should send an [error](#error) message and terminates the
49
+ connection
50
+ * When the initiating peer receives the peer message
51
+ * it stores the `senderId` as the peer ID of the receiving peer.
52
+ * it emits a "peer-candidate" event with the sender ID as the peer
53
+ * if the `selectedProtocolVersion` is anything other than "1" the initiating
54
+ peer sends an [error](#error) message and terminates the connection
55
+ * it begins the sync phase
56
+
57
+
58
+ ### Sync Phase
59
+
60
+ In the sync phase either side may send a [request](#request), [sync](#sync),
61
+ [unavailable](#unavailable), or [ephemeral](#ephemeral) message. Sending these
62
+ corresponds to implementing
63
+ [`NetworkAdapter.send`](https://automerge.org/automerge-repo/classes/_automerge_automerge_repo.NetworkAdapter.html#send)
64
+ and receiving is emitting the [corresponding
65
+ event](https://automerge.org/automerge-repo/interfaces/_automerge_automerge_repo.NetworkAdapterEvents.html)
66
+ from the `NetworkAdapter` on receipt.
67
+
68
+ ### Message Types
69
+
70
+ All messages are encoded using CBOR and are described in this document using
71
+ [cddl](https://datatracker.ietf.org/doc/html/rfc8610)
72
+
73
+ #### Preamble
74
+
75
+ These type definitions are used in every message type
76
+
77
+ ```cddl
78
+ ; The base64 encoded bytes of a Peer ID
79
+ peer_id = str
80
+ ; The possible protocol versions (currently always the string "1")
81
+ protocol_version = "1"
82
+ ; The bytes of an automerge sync message
83
+ sync_message = bstr
84
+ ; The base64 encoded bytes of a document ID
85
+ document_id = str
86
+ ```
87
+
88
+ #### Join
89
+
90
+ Sent by the initiating peer in the [handshake](#handshake) phase.
91
+
92
+ ```cddl
93
+ {
94
+ type: "join",
95
+ senderId: peer_id,
96
+ supportedProtocolVersions: protocol_version
97
+ }
98
+ ```
99
+
100
+ #### Peer
101
+
102
+ Sent by the receiving peer in response to the join message in the
103
+ [handshake](#handshake) phase,
104
+
105
+ ```cddl
106
+ {
107
+ type: "peer",
108
+ senderId: peer_id,
109
+ selectedProtocolVersion: protocol_version,
110
+ targetId: peer_id,
111
+ }
112
+ ```
113
+
114
+ #### Request
115
+
116
+ Sent when the `senderId` is asking to begin sync for the given `documentid`.
117
+ Identical to [sync](#sync) but indicates that the `senderId` would like an
118
+ [unavailable](#unavailable) message if the `targetId` does not have the
119
+ document.
120
+
121
+ ```cddl
122
+ {
123
+ type: "request",
124
+ documentId: document_id,
125
+ ; The peer requesting to begin sync
126
+ senderId: peer_id,
127
+ targetId: peer_id,
128
+ ; The initial automerge sync message from the sender
129
+ data: sync_message
130
+ }
131
+ ```
132
+
133
+ #### Sync
134
+
135
+ Sent any time either peer wants to send a sync message about a given document
136
+
137
+ ```cddl
138
+ {
139
+ type: "sync",
140
+ documentId: document_id,
141
+ ; The peer requesting to begin sync
142
+ senderId: peer_id,
143
+ targetId: peer_id,
144
+ ; The initial automerge sync message from the sender
145
+ data: sync_message
146
+ }
147
+ ```
148
+
149
+ #### Unavailable
150
+
151
+ Sent when a peer wants to indicate to the `targetId` that it doesn't have a
152
+ given document and all of it's peers have also indicated that they don't have
153
+ it
154
+
155
+ ```cddl
156
+ {
157
+ type: "doc-unavailable",
158
+ senderId: peer_id,
159
+ targetId: peer_id,
160
+ documentId: document_id,
161
+ }
162
+ ```
163
+
164
+ #### Ephemeral
165
+
166
+ Sent when a peer wants to send an ephemeral message to another peer
167
+
168
+
169
+ ```cddl
170
+ {
171
+ type: "ephemeral",
172
+ ; The peer who sent this message
173
+ senderId: peer_id,
174
+ ; The target of this message
175
+ targetId: peer_id,
176
+ ; The sequence number of this message within its session
177
+ count: uint,
178
+ ; The unique session identifying this stream of ephemeral messages
179
+ sessionId: str,
180
+ ; The document ID this ephemera relates to
181
+ documentId: document_id,
182
+ ; The data of this message (in practice this is arbitrary CBOR)
183
+ data: bstr
184
+ }
185
+ ```
186
+
187
+ #### Error
188
+
189
+ Sent to inform the other end that there has been a protocol error and the
190
+ connection will close
191
+
192
+ ```cddl
193
+ {
194
+ type: "error",
195
+ message: str,
196
+ }
197
+ ```
@@ -1,5 +1,5 @@
1
- import { type RepoMessage, type PeerId } from "@automerge/automerge-repo";
2
- import { ProtocolVersion } from "./protocolVersion.js";
1
+ import type { Message, PeerId } from "@automerge/automerge-repo";
2
+ import type { ProtocolVersion } from "./protocolVersion.js";
3
3
  /** The sender is disconnecting */
4
4
  export type LeaveMessage = {
5
5
  type: "leave";
@@ -34,7 +34,7 @@ export type ErrorMessage = {
34
34
  targetId: PeerId;
35
35
  };
36
36
  /** A message from the client to the server */
37
- export type FromClientMessage = JoinMessage | LeaveMessage | RepoMessage;
37
+ export type FromClientMessage = JoinMessage | LeaveMessage | Message;
38
38
  /** A message from the server to the client */
39
- export type FromServerMessage = PeerMessage | ErrorMessage | RepoMessage;
39
+ export type FromServerMessage = PeerMessage | ErrorMessage | Message;
40
40
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,2BAA2B,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,+CAA+C;IAC/C,yBAAyB,EAAE,eAAe,EAAE,CAAA;CAC7C,CAAA;AAED,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,uBAAuB,EAAE,eAAe,CAAA;IACxC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAKD,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAA;AAExE,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,CAAA"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,kCAAkC;AAClC,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,+CAA+C;IAC/C,yBAAyB,EAAE,eAAe,EAAE,CAAA;CAC7C,CAAA;AAED,yFAAyF;AACzF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,mEAAmE;IACnE,uBAAuB,EAAE,eAAe,CAAA;IACxC,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAKD,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAA;AAEpE,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo-network-websocket",
3
- "version": "1.0.12",
3
+ "version": "1.0.15",
4
4
  "description": "isomorphic node/browser Websocket network adapter for Automerge Repo",
5
5
  "peerDependencies": {
6
6
  "@automerge/automerge": "^2.1.0"
@@ -16,7 +16,7 @@
16
16
  "test": "vitest"
17
17
  },
18
18
  "dependencies": {
19
- "@automerge/automerge-repo": "^1.0.12",
19
+ "@automerge/automerge-repo": "^1.0.15",
20
20
  "cbor-x": "^1.3.0",
21
21
  "eventemitter3": "^5.0.1",
22
22
  "isomorphic-ws": "^5.0.0",
@@ -33,5 +33,5 @@
33
33
  "publishConfig": {
34
34
  "access": "public"
35
35
  },
36
- "gitHead": "254bad1c774fa2a881265aaad5283af231bf72eb"
36
+ "gitHead": "f60bd2a4594cc23b0ee6debed62aea61fb48ea56"
37
37
  }
package/src/messages.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { type RepoMessage, type PeerId } from "@automerge/automerge-repo"
2
- import { ProtocolVersion } from "./protocolVersion.js"
1
+ import type { Message, PeerId } from "@automerge/automerge-repo"
2
+ import type { ProtocolVersion } from "./protocolVersion.js"
3
3
 
4
4
  /** The sender is disconnecting */
5
5
  export type LeaveMessage = {
@@ -42,7 +42,7 @@ export type ErrorMessage = {
42
42
  // join/leave
43
43
 
44
44
  /** A message from the client to the server */
45
- export type FromClientMessage = JoinMessage | LeaveMessage | RepoMessage
45
+ export type FromClientMessage = JoinMessage | LeaveMessage | Message
46
46
 
47
47
  /** A message from the server to the client */
48
- export type FromServerMessage = PeerMessage | ErrorMessage | RepoMessage
48
+ export type FromServerMessage = PeerMessage | ErrorMessage | Message