@automerge/automerge-repo-network-websocket 1.1.0-alpha.7 → 1.1.1
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 +77 -3
- package/dist/BrowserWebSocketClientAdapter.d.ts +8 -7
- package/dist/BrowserWebSocketClientAdapter.d.ts.map +1 -1
- package/dist/BrowserWebSocketClientAdapter.js +91 -86
- package/dist/NodeWSServerAdapter.d.ts +6 -4
- package/dist/NodeWSServerAdapter.d.ts.map +1 -1
- package/dist/NodeWSServerAdapter.js +105 -102
- package/dist/assert.d.ts +3 -0
- package/dist/assert.d.ts.map +1 -0
- package/dist/assert.js +17 -0
- package/dist/messages.d.ts +4 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +5 -1
- package/dist/toArrayBuffer.d.ts +6 -0
- package/dist/toArrayBuffer.d.ts.map +1 -0
- package/dist/toArrayBuffer.js +8 -0
- package/package.json +4 -3
- package/src/BrowserWebSocketClientAdapter.ts +98 -106
- package/src/NodeWSServerAdapter.ts +119 -123
- package/src/assert.ts +28 -0
- package/src/messages.ts +18 -3
- package/src/toArrayBuffer.ts +8 -0
- package/test/Websocket.test.ts +350 -125
package/README.md
CHANGED
|
@@ -17,9 +17,7 @@ is the server.
|
|
|
17
17
|
|
|
18
18
|
### Overview
|
|
19
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.
|
|
20
|
+
The websocket wire protocol consists of a handshake where each peer tells the other what their peer ID - and some other metadata - is followed by the sync loop where each peer can send the other sync messages and ephemeral messages.
|
|
23
21
|
|
|
24
22
|
### Handshake
|
|
25
23
|
|
|
@@ -54,6 +52,10 @@ Handshake is the following steps:
|
|
|
54
52
|
peer sends an [error](#error) message and terminates the connection
|
|
55
53
|
* it begins the sync phase
|
|
56
54
|
|
|
55
|
+
#### Peer IDs and storage IDs
|
|
56
|
+
|
|
57
|
+
The peer ID is an ephemeral ID which is assumed to only live for the lifetime of the process which advertises the given ID (e.g. a browser tab). Peers may optionally advertise a storage ID in the `join` and `peer` messages, this is an ID which is assumed to be tied to a persistent storage of some kind (e.g. an IndexedDB in a browser). Many peer IDs can advertise the same storage ID (as in the case of many browser tabs). The use of a storage ID allows other peers to know whether to save and reload sync states for a given peer (if the peer advertises a storage ID, then save and reload the sync state attached to that storage ID).
|
|
58
|
+
|
|
57
59
|
|
|
58
60
|
### Sync Phase
|
|
59
61
|
|
|
@@ -65,6 +67,22 @@ and receiving is emitting the [corresponding
|
|
|
65
67
|
event](https://automerge.org/automerge-repo/interfaces/_automerge_automerge_repo.NetworkAdapterEvents.html)
|
|
66
68
|
from the `NetworkAdapter` on receipt.
|
|
67
69
|
|
|
70
|
+
#### Remote heads gossiping
|
|
71
|
+
|
|
72
|
+
In some cases peers wish to know about the state of peers who are separated from them by several intermediate peers. For example, a tab running a text editor may wish to show whether the contents of the editor are up to date with respect to a tab running in a browser on another users device. This is achieved by gossiping remote heads across intermediate nodes. The logic for this is the following:
|
|
73
|
+
|
|
74
|
+
* For a given connection each peer maintains a list of the storage IDs the remote peer is interested in (note this is storage IDs, not peer IDs)
|
|
75
|
+
* Any peer can send a [`remote-subscription-changed`](#remote-subscription-changed) message to change the set of storage IDs they want the recipient to watch on the sender's behalf
|
|
76
|
+
* Any time a peer receives a sync message it checks:
|
|
77
|
+
* Is the sync message from a peer with a storage ID which some other remote peer has registered interest in
|
|
78
|
+
* Is the remote peer permitted access to the document which the message pertains to (i.e. either the `sharePolicy` return `true` or the local peer is already syncing the document with the remote)
|
|
79
|
+
* The local peer sends a [`remote-heads-changed`](#remote-heads-changed) message to each remote peer who passes these checks
|
|
80
|
+
* Additionally, whenever the local peer receives a `remote-heads-changed` message it performs the same checks and additionally checks if the timestamp on the `remote-heads-changed` message is greater than the last timestamp for the same storage ID/document combination and if so it forwards it.
|
|
81
|
+
|
|
82
|
+
In the `browser <-> sync server <-> browser` text editor example above each browser tab would send a `remote-subscription-changed` message to the sync server adding the other browsers storage ID (presumably communicated out of band) to their subscriptions with the sync server. The sync server will then send `remote-heads-changed` messages to each tab when their heads change.
|
|
83
|
+
|
|
84
|
+
In a more elaborate example such as `browser <-> sync server <-> sync server <-> browser` the intermediate sync servers could be configured to have their `sharePolicy` return `true` for every document when syncing with each other so that `remote-heads-changed` messages are forwarded between them unconditionally, allowing the browser tabs to still learn of each others heads.
|
|
85
|
+
|
|
68
86
|
### Message Types
|
|
69
87
|
|
|
70
88
|
All messages are encoded using CBOR and are described in this document using
|
|
@@ -77,12 +95,21 @@ These type definitions are used in every message type
|
|
|
77
95
|
```cddl
|
|
78
96
|
; The base64 encoded bytes of a Peer ID
|
|
79
97
|
peer_id = str
|
|
98
|
+
; The base64 encoded bytes of a Storage ID
|
|
99
|
+
storage_id = str
|
|
80
100
|
; The possible protocol versions (currently always the string "1")
|
|
81
101
|
protocol_version = "1"
|
|
82
102
|
; The bytes of an automerge sync message
|
|
83
103
|
sync_message = bstr
|
|
84
104
|
; The base58check encoded bytes of a document ID
|
|
85
105
|
document_id = str
|
|
106
|
+
; Metadata sent in either the join or peer message types
|
|
107
|
+
peer_metadata = {
|
|
108
|
+
; The storage ID of this peer
|
|
109
|
+
? storageId: storage_id,
|
|
110
|
+
; Whether the sender expects to connect again with this storage ID
|
|
111
|
+
isEphemeral: bool
|
|
112
|
+
}
|
|
86
113
|
```
|
|
87
114
|
|
|
88
115
|
#### Join
|
|
@@ -94,6 +121,7 @@ Sent by the initiating peer in the [handshake](#handshake) phase.
|
|
|
94
121
|
type: "join",
|
|
95
122
|
senderId: peer_id,
|
|
96
123
|
supportedProtocolVersions: protocol_version
|
|
124
|
+
? metadata: peer_metadata,
|
|
97
125
|
}
|
|
98
126
|
```
|
|
99
127
|
|
|
@@ -108,6 +136,7 @@ Sent by the receiving peer in response to the join message in the
|
|
|
108
136
|
senderId: peer_id,
|
|
109
137
|
selectedProtocolVersion: protocol_version,
|
|
110
138
|
targetId: peer_id,
|
|
139
|
+
? metadata: peer_metadata,
|
|
111
140
|
}
|
|
112
141
|
```
|
|
113
142
|
|
|
@@ -195,3 +224,48 @@ connection will close
|
|
|
195
224
|
message: str,
|
|
196
225
|
}
|
|
197
226
|
```
|
|
227
|
+
|
|
228
|
+
#### Remote subscription changed
|
|
229
|
+
|
|
230
|
+
Sent when the sender wishes to change the set of storage IDs they wish to be notified of when the given remotes heads change.
|
|
231
|
+
|
|
232
|
+
```cddl
|
|
233
|
+
{
|
|
234
|
+
type: "remote-subscription-change"
|
|
235
|
+
senderId: peer_id
|
|
236
|
+
targetId: peer_id
|
|
237
|
+
|
|
238
|
+
; The storage IDs to add to the subscription
|
|
239
|
+
? add: [* storage_id]
|
|
240
|
+
|
|
241
|
+
; The storage IDs to remove from the subscription
|
|
242
|
+
remove: [* storage_id]
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### Remote heads changed
|
|
247
|
+
|
|
248
|
+
Sent when the sender wishes to inform the receiver that a peer with a storage ID in the receivers remote heads subscription has changed heads. This is either sent when the local peer receives a new sync message directly from the listened-to peer, or when the local peer receives a `remote-heads-changed` message relating to the listened-to peer from another peer.
|
|
249
|
+
|
|
250
|
+
```cddl
|
|
251
|
+
{
|
|
252
|
+
type: "remote-heads-changed"
|
|
253
|
+
senderId: peer_id
|
|
254
|
+
targetId: peer_id
|
|
255
|
+
|
|
256
|
+
; The document ID of the document that has changed
|
|
257
|
+
documentId: document_id
|
|
258
|
+
|
|
259
|
+
; A map from storage ID to the heads advertised for a given storage ID
|
|
260
|
+
newHeads: {
|
|
261
|
+
* storage_id => {
|
|
262
|
+
; The heads of the new document for the given storage ID as
|
|
263
|
+
; a list of base64 encoded SHA2 hashes
|
|
264
|
+
heads: [* string]
|
|
265
|
+
; The local time on the node which initially sent the remote-heads-changed
|
|
266
|
+
; message as milliseconds since the unix epoch
|
|
267
|
+
timestamp: uint
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="ws" />
|
|
2
|
-
import { NetworkAdapter,
|
|
2
|
+
import { NetworkAdapter, PeerId, PeerMetadata } from "@automerge/automerge-repo";
|
|
3
3
|
import WebSocket from "isomorphic-ws";
|
|
4
4
|
import { FromClientMessage } from "./messages.js";
|
|
5
5
|
declare abstract class WebSocketNetworkAdapter extends NetworkAdapter {
|
|
@@ -7,19 +7,20 @@ declare abstract class WebSocketNetworkAdapter extends NetworkAdapter {
|
|
|
7
7
|
}
|
|
8
8
|
export declare class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
9
9
|
#private;
|
|
10
|
-
|
|
10
|
+
readonly url: string;
|
|
11
|
+
readonly retryInterval: number;
|
|
11
12
|
remotePeerId?: PeerId;
|
|
12
|
-
url: string;
|
|
13
|
-
|
|
14
|
-
connect(peerId: PeerId, peerMetadata: PeerMetadata): void;
|
|
13
|
+
constructor(url: string, retryInterval?: number);
|
|
14
|
+
connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
15
15
|
onOpen: () => void;
|
|
16
16
|
onClose: () => void;
|
|
17
17
|
onMessage: (event: WebSocket.MessageEvent) => void;
|
|
18
|
+
onError: (event: WebSocket.ErrorEvent) => void;
|
|
18
19
|
join(): void;
|
|
19
20
|
disconnect(): void;
|
|
20
21
|
send(message: FromClientMessage): void;
|
|
21
|
-
|
|
22
|
-
receiveMessage(
|
|
22
|
+
peerCandidate(remotePeerId: PeerId, peerMetadata: PeerMetadata): void;
|
|
23
|
+
receiveMessage(messageBytes: Uint8Array): void;
|
|
23
24
|
}
|
|
24
25
|
export {};
|
|
25
26
|
//# sourceMappingURL=BrowserWebSocketClientAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowserWebSocketClientAdapter.d.ts","sourceRoot":"","sources":["../src/BrowserWebSocketClientAdapter.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"BrowserWebSocketClientAdapter.d.ts","sourceRoot":"","sources":["../src/BrowserWebSocketClientAdapter.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,cAAc,EACd,MAAM,EACN,YAAY,EAEb,MAAM,2BAA2B,CAAA;AAClC,OAAO,SAAS,MAAM,eAAe,CAAA;AAIrC,OAAO,EACL,iBAAiB,EAKlB,MAAM,eAAe,CAAA;AAKtB,uBAAe,uBAAwB,SAAQ,cAAc;IAC3D,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB;AAED,qBAAa,6BAA8B,SAAQ,uBAAuB;;aAQtD,GAAG,EAAE,MAAM;aACX,aAAa;IAJ/B,YAAY,CAAC,EAAE,MAAM,CAAA;gBAGH,GAAG,EAAE,MAAM,EACX,aAAa,SAAO;IAMtC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY;IAqCnD,MAAM,aAKL;IAGD,OAAO,aAWN;IAED,SAAS,UAAW,sBAAsB,UAEzC;IAED,OAAO,UAAW,oBAAoB,UAQrC;IAQD,IAAI;IAUJ,UAAU;IAMV,IAAI,CAAC,OAAO,EAAE,iBAAiB;IAY/B,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY;IAU9D,cAAc,CAAC,YAAY,EAAE,UAAU;CAiBxC"}
|
|
@@ -1,140 +1,145 @@
|
|
|
1
1
|
import { NetworkAdapter, cbor, } from "@automerge/automerge-repo";
|
|
2
2
|
import WebSocket from "isomorphic-ws";
|
|
3
3
|
import debug from "debug";
|
|
4
|
+
import { isErrorMessage, isPeerMessage, } from "./messages.js";
|
|
4
5
|
import { ProtocolV1 } from "./protocolVersion.js";
|
|
5
|
-
|
|
6
|
+
import { assert } from "./assert.js";
|
|
7
|
+
import { toArrayBuffer } from "./toArrayBuffer.js";
|
|
6
8
|
class WebSocketNetworkAdapter extends NetworkAdapter {
|
|
7
9
|
socket;
|
|
8
10
|
}
|
|
9
11
|
export class BrowserWebSocketClientAdapter extends WebSocketNetworkAdapter {
|
|
10
|
-
// Type trickery required for platform independence,
|
|
11
|
-
// see https://stackoverflow.com/questions/45802988/typescript-use-correct-version-of-settimeout-node-vs-window
|
|
12
|
-
timerId;
|
|
13
|
-
remotePeerId; // this adapter only connects to one remote client at a time
|
|
14
|
-
#startupComplete = false;
|
|
15
12
|
url;
|
|
16
|
-
|
|
13
|
+
retryInterval;
|
|
14
|
+
#isReady = false;
|
|
15
|
+
#retryIntervalId;
|
|
16
|
+
#log = debug("automerge-repo:websocket:browser");
|
|
17
|
+
remotePeerId; // this adapter only connects to one remote client at a time
|
|
18
|
+
constructor(url, retryInterval = 5000) {
|
|
17
19
|
super();
|
|
18
20
|
this.url = url;
|
|
21
|
+
this.retryInterval = retryInterval;
|
|
22
|
+
this.#log = this.#log.extend(url);
|
|
19
23
|
}
|
|
20
24
|
connect(peerId, peerMetadata) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
if (!this.socket || !this.peerId) {
|
|
26
|
+
// first time connecting
|
|
27
|
+
this.#log("connecting");
|
|
28
|
+
this.peerId = peerId;
|
|
29
|
+
this.peerMetadata = peerMetadata ?? {};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.#log("reconnecting");
|
|
33
|
+
assert(peerId === this.peerId);
|
|
34
|
+
// Remove the old event listeners before creating a new connection.
|
|
24
35
|
this.socket.removeEventListener("open", this.onOpen);
|
|
25
36
|
this.socket.removeEventListener("close", this.onClose);
|
|
26
37
|
this.socket.removeEventListener("message", this.onMessage);
|
|
38
|
+
this.socket.removeEventListener("error", this.onError);
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
// Wire up retries
|
|
41
|
+
if (!this.#retryIntervalId)
|
|
42
|
+
this.#retryIntervalId = setInterval(() => {
|
|
43
|
+
this.connect(peerId, peerMetadata);
|
|
44
|
+
}, this.retryInterval);
|
|
33
45
|
this.socket = new WebSocket(this.url);
|
|
34
46
|
this.socket.binaryType = "arraybuffer";
|
|
35
47
|
this.socket.addEventListener("open", this.onOpen);
|
|
36
48
|
this.socket.addEventListener("close", this.onClose);
|
|
37
49
|
this.socket.addEventListener("message", this.onMessage);
|
|
38
|
-
|
|
50
|
+
this.socket.addEventListener("error", this.onError);
|
|
51
|
+
// Mark this adapter as ready if we haven't received an ack in 1 second.
|
|
39
52
|
// We might hear back from the other end at some point but we shouldn't
|
|
40
53
|
// hold up marking things as unavailable for any longer
|
|
41
|
-
setTimeout(() =>
|
|
42
|
-
if (!this.#startupComplete) {
|
|
43
|
-
this.#startupComplete = true;
|
|
44
|
-
this.emit("ready", { network: this });
|
|
45
|
-
}
|
|
46
|
-
}, 1000);
|
|
54
|
+
setTimeout(() => this.#ready(), 1000);
|
|
47
55
|
this.join();
|
|
48
56
|
}
|
|
49
57
|
onOpen = () => {
|
|
50
|
-
log(
|
|
51
|
-
clearInterval(this
|
|
52
|
-
this
|
|
53
|
-
this.
|
|
58
|
+
this.#log("open");
|
|
59
|
+
clearInterval(this.#retryIntervalId);
|
|
60
|
+
this.#retryIntervalId = undefined;
|
|
61
|
+
this.join();
|
|
54
62
|
};
|
|
55
63
|
// When a socket closes, or disconnects, remove it from the array.
|
|
56
64
|
onClose = () => {
|
|
57
|
-
log(
|
|
58
|
-
if (this.remotePeerId)
|
|
65
|
+
this.#log("close");
|
|
66
|
+
if (this.remotePeerId)
|
|
59
67
|
this.emit("peer-disconnected", { peerId: this.remotePeerId });
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
if (this.retryInterval > 0 && !this.#retryIntervalId)
|
|
69
|
+
// try to reconnect
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
assert(this.peerId);
|
|
72
|
+
return this.connect(this.peerId, this.peerMetadata);
|
|
73
|
+
}, this.retryInterval);
|
|
66
74
|
};
|
|
67
75
|
onMessage = (event) => {
|
|
68
76
|
this.receiveMessage(event.data);
|
|
69
77
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
78
|
+
onError = (event) => {
|
|
79
|
+
const { code } = event.error;
|
|
80
|
+
if (code === "ECONNREFUSED") {
|
|
81
|
+
this.#log("Connection refused, retrying...");
|
|
73
82
|
}
|
|
83
|
+
else {
|
|
84
|
+
/* c8 ignore next */
|
|
85
|
+
throw event.error;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
#ready() {
|
|
89
|
+
if (this.#isReady)
|
|
90
|
+
return;
|
|
91
|
+
this.#isReady = true;
|
|
92
|
+
this.emit("ready", { network: this });
|
|
93
|
+
}
|
|
94
|
+
join() {
|
|
95
|
+
assert(this.peerId);
|
|
96
|
+
assert(this.socket);
|
|
74
97
|
if (this.socket.readyState === WebSocket.OPEN) {
|
|
75
98
|
this.send(joinMessage(this.peerId, this.peerMetadata));
|
|
76
99
|
}
|
|
77
100
|
else {
|
|
78
|
-
//
|
|
101
|
+
// We'll try again in the `onOpen` handler
|
|
79
102
|
}
|
|
80
103
|
}
|
|
81
104
|
disconnect() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
105
|
+
assert(this.peerId);
|
|
106
|
+
assert(this.socket);
|
|
85
107
|
this.send({ type: "leave", senderId: this.peerId });
|
|
86
108
|
}
|
|
87
109
|
send(message) {
|
|
88
|
-
if ("data" in message && message.data
|
|
89
|
-
throw new Error("
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
|
|
95
|
-
throw new Error("Websocket Socket not ready!");
|
|
96
|
-
}
|
|
110
|
+
if ("data" in message && message.data?.byteLength === 0)
|
|
111
|
+
throw new Error("Tried to send a zero-length message");
|
|
112
|
+
assert(this.peerId);
|
|
113
|
+
assert(this.socket);
|
|
114
|
+
if (this.socket.readyState !== WebSocket.OPEN)
|
|
115
|
+
throw new Error(`Websocket not ready (${this.socket.readyState})`);
|
|
97
116
|
const encoded = cbor.encode(message);
|
|
98
|
-
|
|
99
|
-
// underlying buffer even if we just have a uint8array view on it
|
|
100
|
-
const arrayBuf = encoded.buffer.slice(encoded.byteOffset, encoded.byteOffset + encoded.byteLength);
|
|
101
|
-
this.socket?.send(arrayBuf);
|
|
117
|
+
this.socket.send(toArrayBuffer(encoded));
|
|
102
118
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
this.emit("ready", { network: this });
|
|
112
|
-
}
|
|
113
|
-
this.remotePeerId = peerId;
|
|
114
|
-
this.emit("peer-candidate", { peerId, peerMetadata });
|
|
119
|
+
peerCandidate(remotePeerId, peerMetadata) {
|
|
120
|
+
assert(this.socket);
|
|
121
|
+
this.#ready();
|
|
122
|
+
this.remotePeerId = remotePeerId;
|
|
123
|
+
this.emit("peer-candidate", {
|
|
124
|
+
peerId: remotePeerId,
|
|
125
|
+
peerMetadata,
|
|
126
|
+
});
|
|
115
127
|
}
|
|
116
|
-
receiveMessage(
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (!socket) {
|
|
121
|
-
throw new Error("Missing socket at receiveMessage");
|
|
122
|
-
}
|
|
123
|
-
if (message.byteLength === 0) {
|
|
128
|
+
receiveMessage(messageBytes) {
|
|
129
|
+
const message = cbor.decode(new Uint8Array(messageBytes));
|
|
130
|
+
assert(this.socket);
|
|
131
|
+
if (messageBytes.byteLength === 0)
|
|
124
132
|
throw new Error("received a zero-length message");
|
|
133
|
+
if (isPeerMessage(message)) {
|
|
134
|
+
const { peerMetadata } = message;
|
|
135
|
+
this.#log(`peer: ${message.senderId}`);
|
|
136
|
+
this.peerCandidate(message.senderId, peerMetadata);
|
|
125
137
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
case "error":
|
|
134
|
-
log(`error: ${decoded.message}`);
|
|
135
|
-
break;
|
|
136
|
-
default:
|
|
137
|
-
this.emit("message", decoded);
|
|
138
|
+
else if (isErrorMessage(message)) {
|
|
139
|
+
this.#log(`error: ${message.message}`);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this.emit("message", message);
|
|
138
143
|
}
|
|
139
144
|
}
|
|
140
145
|
}
|
|
@@ -4,14 +4,16 @@ import { type WebSocketServer } from "isomorphic-ws";
|
|
|
4
4
|
import { NetworkAdapter, type PeerMetadata, type PeerId } from "@automerge/automerge-repo";
|
|
5
5
|
import { FromServerMessage } from "./messages.js";
|
|
6
6
|
export declare class NodeWSServerAdapter extends NetworkAdapter {
|
|
7
|
-
|
|
7
|
+
#private;
|
|
8
|
+
private server;
|
|
9
|
+
private keepAliveInterval;
|
|
8
10
|
sockets: {
|
|
9
11
|
[peerId: PeerId]: WebSocket;
|
|
10
12
|
};
|
|
11
|
-
constructor(server: WebSocketServer);
|
|
12
|
-
connect(peerId: PeerId, peerMetadata
|
|
13
|
+
constructor(server: WebSocketServer, keepAliveInterval?: number);
|
|
14
|
+
connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
13
15
|
disconnect(): void;
|
|
14
16
|
send(message: FromServerMessage): void;
|
|
15
|
-
receiveMessage(
|
|
17
|
+
receiveMessage(messageBytes: Uint8Array, socket: WebSocket): void;
|
|
16
18
|
}
|
|
17
19
|
//# sourceMappingURL=NodeWSServerAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeWSServerAdapter.d.ts","sourceRoot":"","sources":["../src/NodeWSServerAdapter.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD,OAAO,EAEL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAA;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"NodeWSServerAdapter.d.ts","sourceRoot":"","sources":["../src/NodeWSServerAdapter.ts"],"names":[],"mappings":";AAAA,OAAO,SAAS,MAAM,eAAe,CAAA;AACrC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD,OAAO,EAEL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,2BAA2B,CAAA;AAClC,OAAO,EAEL,iBAAiB,EAGlB,MAAM,eAAe,CAAA;AAOtB,qBAAa,mBAAoB,SAAQ,cAAc;;IAInD,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,iBAAiB;IAJ3B,OAAO,EAAE;QAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAK;gBAGnC,MAAM,EAAE,eAAe,EACvB,iBAAiB,SAAO;IAKlC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY;IAyCnD,UAAU;IAQV,IAAI,CAAC,OAAO,EAAE,iBAAiB;IAqB/B,cAAc,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS;CA0E3D"}
|