@automerge/automerge-repo 1.0.6 → 1.0.7

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.
Files changed (63) hide show
  1. package/.eslintrc +1 -1
  2. package/dist/DocHandle.d.ts +7 -7
  3. package/dist/DocHandle.d.ts.map +1 -1
  4. package/dist/DocHandle.js +3 -7
  5. package/dist/EphemeralData.d.ts +2 -2
  6. package/dist/EphemeralData.d.ts.map +1 -1
  7. package/dist/Repo.d.ts.map +1 -1
  8. package/dist/Repo.js +7 -11
  9. package/dist/helpers/cbor.d.ts +2 -2
  10. package/dist/helpers/cbor.d.ts.map +1 -1
  11. package/dist/helpers/cbor.js +1 -1
  12. package/dist/helpers/pause.d.ts.map +1 -1
  13. package/dist/helpers/pause.js +3 -1
  14. package/dist/helpers/tests/network-adapter-tests.d.ts.map +1 -1
  15. package/dist/helpers/tests/network-adapter-tests.js +2 -2
  16. package/dist/index.d.ts +11 -9
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +4 -4
  19. package/dist/network/NetworkAdapter.d.ts +3 -3
  20. package/dist/network/NetworkAdapter.d.ts.map +1 -1
  21. package/dist/network/NetworkSubsystem.d.ts +2 -2
  22. package/dist/network/NetworkSubsystem.d.ts.map +1 -1
  23. package/dist/network/NetworkSubsystem.js +30 -18
  24. package/dist/network/messages.d.ts +38 -68
  25. package/dist/network/messages.d.ts.map +1 -1
  26. package/dist/network/messages.js +13 -21
  27. package/dist/storage/StorageSubsystem.js +7 -7
  28. package/dist/synchronizer/CollectionSynchronizer.d.ts +3 -3
  29. package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
  30. package/dist/synchronizer/CollectionSynchronizer.js +2 -2
  31. package/dist/synchronizer/DocSynchronizer.d.ts +3 -3
  32. package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
  33. package/dist/synchronizer/DocSynchronizer.js +22 -29
  34. package/dist/synchronizer/Synchronizer.d.ts +2 -2
  35. package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
  36. package/dist/types.d.ts +5 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/package.json +5 -13
  39. package/src/DocHandle.ts +9 -11
  40. package/src/EphemeralData.ts +2 -2
  41. package/src/Repo.ts +10 -14
  42. package/src/helpers/cbor.ts +4 -4
  43. package/src/helpers/pause.ts +7 -2
  44. package/src/helpers/tests/network-adapter-tests.ts +3 -3
  45. package/src/helpers/withTimeout.ts +2 -2
  46. package/src/index.ts +36 -29
  47. package/src/network/NetworkAdapter.ts +7 -3
  48. package/src/network/NetworkSubsystem.ts +31 -23
  49. package/src/network/messages.ts +88 -151
  50. package/src/storage/StorageSubsystem.ts +8 -8
  51. package/src/synchronizer/CollectionSynchronizer.ts +6 -15
  52. package/src/synchronizer/DocSynchronizer.ts +34 -48
  53. package/src/synchronizer/Synchronizer.ts +2 -2
  54. package/src/types.ts +8 -3
  55. package/test/CollectionSynchronizer.test.ts +58 -53
  56. package/test/DocHandle.test.ts +35 -36
  57. package/test/DocSynchronizer.test.ts +9 -8
  58. package/test/Network.test.ts +1 -0
  59. package/test/Repo.test.ts +177 -97
  60. package/test/StorageSubsystem.test.ts +6 -9
  61. package/test/tsconfig.json +8 -0
  62. package/typedoc.json +3 -3
  63. package/.mocharc.json +0 -5
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from "eventemitter3"
2
2
  import { PeerId } from "../types.js"
3
- import { Message } from "./messages.js"
3
+ import { RepoMessage } from "./messages.js"
4
4
 
5
5
  /** An interface representing some way to connect to other peers
6
6
  *
@@ -22,7 +22,7 @@ export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents>
22
22
  *
23
23
  * @argument message - the message to send
24
24
  */
25
- abstract send(message: Message): void
25
+ abstract send(message: RepoMessage): void
26
26
 
27
27
  /** Called by the {@link Repo} to disconnect from the network */
28
28
  abstract disconnect(): void
@@ -33,14 +33,18 @@ export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents>
33
33
  export interface NetworkAdapterEvents {
34
34
  /** Emitted when the network is ready to be used */
35
35
  ready: (payload: OpenPayload) => void
36
+
36
37
  /** Emitted when the network is closed */
37
38
  close: () => void
39
+
38
40
  /** Emitted when the network adapter learns about a new peer */
39
41
  "peer-candidate": (payload: PeerCandidatePayload) => void
42
+
40
43
  /** Emitted when the network adapter learns that a peer has disconnected */
41
44
  "peer-disconnected": (payload: PeerDisconnectedPayload) => void
45
+
42
46
  /** Emitted when the network adapter receives a message from a peer */
43
- message: (payload: Message) => void
47
+ message: (payload: RepoMessage) => void
44
48
  }
45
49
 
46
50
  export interface OpenPayload {
@@ -1,18 +1,15 @@
1
+ import debug from "debug"
1
2
  import { EventEmitter } from "eventemitter3"
2
- import { PeerId } from "../types.js"
3
+ import { PeerId, SessionId } from "../types.js"
3
4
  import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js"
4
-
5
5
  import {
6
6
  EphemeralMessage,
7
- isEphemeralMessage,
8
- isValidMessage,
9
- Message,
7
+ RepoMessage,
10
8
  MessageContents,
9
+ isEphemeralMessage,
10
+ isValidRepoMessage,
11
11
  } from "./messages.js"
12
12
 
13
- import debug from "debug"
14
- import { SessionId } from "../EphemeralData.js"
15
-
16
13
  type EphemeralMessageSource = `${PeerId}:${SessionId}`
17
14
 
18
15
  const getEphemeralMessageSource = (message: EphemeralMessage) =>
@@ -69,7 +66,7 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
69
66
  })
70
67
 
71
68
  networkAdapter.on("message", msg => {
72
- if (!isValidMessage(msg)) {
69
+ if (!isValidRepoMessage(msg)) {
73
70
  this.#log(`invalid message: ${JSON.stringify(msg)}`)
74
71
  return
75
72
  }
@@ -110,25 +107,36 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
110
107
  this.#log(`Tried to send message but peer not found: ${message.targetId}`)
111
108
  return
112
109
  }
113
- this.#log(`Sending message to ${message.targetId}`)
114
110
 
115
- if (isEphemeralMessage(message)) {
116
- const outbound =
117
- "count" in message
118
- ? message
119
- : {
111
+ /** Messages come in without a senderId and other required information; this is where we make
112
+ * sure they have everything they need.
113
+ */
114
+ const prepareMessage = (message: MessageContents): RepoMessage => {
115
+ if (message.type === "ephemeral") {
116
+ if ("count" in message) {
117
+ // existing ephemeral message from another peer; pass on without changes
118
+ return message as EphemeralMessage
119
+ } else {
120
+ // new ephemeral message from us; add our senderId as well as a counter and session id
121
+ return {
120
122
  ...message,
121
123
  count: ++this.#count,
122
124
  sessionId: this.#sessionId,
123
125
  senderId: this.peerId,
124
- }
125
- this.#log("Ephemeral message", outbound)
126
- peer.send(outbound)
127
- } else {
128
- const outbound = { ...message, senderId: this.peerId }
129
- this.#log("Sync message", outbound)
130
- peer.send(outbound)
126
+ } as EphemeralMessage
127
+ }
128
+ } else {
129
+ // other message type; just add our senderId
130
+ return {
131
+ ...message,
132
+ senderId: this.peerId,
133
+ } as RepoMessage
134
+ }
131
135
  }
136
+
137
+ const outbound = prepareMessage(message)
138
+ this.#log("sending message", outbound)
139
+ peer.send(outbound as RepoMessage)
132
140
  }
133
141
 
134
142
  isReady = () => {
@@ -157,7 +165,7 @@ function randomPeerId() {
157
165
  export interface NetworkSubsystemEvents {
158
166
  peer: (payload: PeerPayload) => void
159
167
  "peer-disconnected": (payload: PeerDisconnectedPayload) => void
160
- message: (payload: Message) => void
168
+ message: (payload: RepoMessage) => void
161
169
  ready: () => void
162
170
  }
163
171
 
@@ -1,161 +1,70 @@
1
- // utilities
2
- import { SessionId } from "../EphemeralData.js"
3
- export { type SessionId } from "../EphemeralData.js"
4
- import { DocumentId, PeerId } from "../types.js"
5
-
6
- export function isValidMessage(
7
- message: NetworkAdapterMessage
8
- ): message is
9
- | SyncMessage
10
- | EphemeralMessage
11
- | RequestMessage
12
- | DocumentUnavailableMessage {
13
- return (
14
- typeof message === "object" &&
15
- typeof message.type === "string" &&
16
- typeof message.senderId === "string" &&
17
- (isSyncMessage(message) ||
18
- isEphemeralMessage(message) ||
19
- isRequestMessage(message) ||
20
- isDocumentUnavailableMessage(message))
21
- )
22
- }
23
-
24
- export function isDocumentUnavailableMessage(
25
- message: NetworkAdapterMessage
26
- ): message is DocumentUnavailableMessage {
27
- return message.type === "doc-unavailable"
28
- }
29
-
30
- export function isRequestMessage(
31
- message: NetworkAdapterMessage
32
- ): message is RequestMessage {
33
- return message.type === "request"
34
- }
35
-
36
- export function isSyncMessage(
37
- message: NetworkAdapterMessage
38
- ): message is SyncMessage {
39
- return message.type === "sync"
40
- }
41
-
42
- export function isEphemeralMessage(
43
- message: NetworkAdapterMessage | MessageContents
44
- ): message is EphemeralMessage | EphemeralMessageContents {
45
- return message.type === "ephemeral"
46
- }
47
-
48
- export interface SyncMessageEnvelope {
49
- senderId: PeerId
50
- }
1
+ import { DocumentId, PeerId, SessionId } from "../types.js"
51
2
 
52
- export interface SyncMessageContents {
53
- type: "sync"
54
- data: Uint8Array
55
- targetId: PeerId
56
- documentId: DocumentId
57
- }
58
-
59
- type static_assert<T extends true> = never
60
-
61
- // export type SyncMessage = SyncMessageEnvelope & SyncMessageContents
62
- // we inline the definitions here rather than using the above type alias because
63
- // otherwise typedoc can't produce nice docs. We use this `static_assert` thing
64
- // to make sure the types continue to line up though.
65
- type _check_sync_message = static_assert<SyncMessage extends SyncMessageEnvelope & SyncMessageContents ? true : false>
66
3
  /**
67
4
  * A sync message for a particular document
68
5
  */
69
6
  export type SyncMessage = {
7
+ type: "sync"
8
+
70
9
  /** The peer ID of the sender of this message */
71
10
  senderId: PeerId
72
- type: "sync"
73
- /** The automerge sync message */
74
- data: Uint8Array
11
+
75
12
  /** The peer ID of the recipient of this message */
76
13
  targetId: PeerId
77
- /** The document ID of the document this message is for */
78
- documentId: DocumentId
79
- }
80
14
 
15
+ /** The automerge sync message */
16
+ data: Uint8Array
81
17
 
82
- export interface EphemeralMessageEnvelope {
83
- senderId: PeerId
84
- count: number
85
- sessionId: SessionId
86
- }
87
-
88
- export interface EphemeralMessageContents {
89
- type: "ephemeral"
90
- targetId: PeerId
18
+ /** The document ID of the document this message is for */
91
19
  documentId: DocumentId
92
- data: Uint8Array
93
20
  }
94
21
 
95
- // export type EphemeralMessage = EphemeralMessageEnvelope & EphemeralMessageContents
96
- // Inline definitions to get good docs, but check the types line up
97
- type _check_ephemeral_message = static_assert<EphemeralMessage extends EphemeralMessageEnvelope & EphemeralMessageContents ? true : false>
98
-
99
- /** An ephemeral message
100
- *
22
+ /** An ephemeral message
23
+ *
101
24
  * @remarks
102
25
  * Ephemeral messages are not persisted anywhere and have no particular
103
- * structure. `automerge-repo` will gossip them around, in order to avoid
26
+ * structure. `automerge-repo` will gossip them around, in order to avoid
104
27
  * eternal loops of ephemeral messages every message has a session ID, which
105
28
  * is a random number generated by the sender at startup time, and a sequence
106
29
  * number. The combination of these two things allows us to discard messages
107
30
  * we have already seen.
108
31
  * */
109
32
  export type EphemeralMessage = {
110
- /** The ID of the peer who sent this message */
33
+ type: "ephemeral"
34
+
35
+ /** The peer ID of the sender of this message */
111
36
  senderId: PeerId
37
+
38
+ /** The peer ID of the recipient of this message */
39
+ targetId: PeerId
40
+
112
41
  /** A sequence number which must be incremented for each message sent by this peer */
113
42
  count: number
43
+
114
44
  /** The ID of the session this message is part of. The sequence number for a given session always increases */
115
45
  sessionId: SessionId
116
- type: "ephemeral"
117
- /** The peer this message is for */
118
- targetId: PeerId
46
+
119
47
  /** The document ID this message pertains to */
120
48
  documentId: DocumentId
49
+
121
50
  /** The actual data of the message */
122
51
  data: Uint8Array
123
52
  }
124
53
 
125
- export interface DocumentUnavailableMessageContents {
126
- type: "doc-unavailable"
127
- documentId: DocumentId
128
- targetId: PeerId
129
- }
130
-
131
-
132
- // export type DocumentUnavailableMessage = SyncMessageEnvelope & DocumentUnavailableMessageContents
133
- // Inline definitions to get good docs, but check the types line up
134
- type _check_doc_unavailable = static_assert<DocumentUnavailableMessage extends SyncMessageEnvelope & DocumentUnavailableMessageContents ? true : false>
135
54
  /** Sent by a {@link Repo} to indicate that it does not have the document and none of it's connected peers do either */
136
55
  export type DocumentUnavailableMessage = {
137
- /** The peer who sent this message */
138
- senderId: PeerId
139
56
  type: "doc-unavailable"
140
- /** The document which the peer claims it doesn't have */
141
- documentId: DocumentId
142
- /** The peer this message is for */
143
- targetId: PeerId
144
- }
145
57
 
146
- export interface RequestMessageContents {
147
- type: "request"
148
- data: Uint8Array
58
+ /** The peer ID of the sender of this message */
59
+ senderId: PeerId
60
+
61
+ /** The peer ID of the recipient of this message */
149
62
  targetId: PeerId
63
+
64
+ /** The document which the peer claims it doesn't have */
150
65
  documentId: DocumentId
151
66
  }
152
67
 
153
- // export type RequestMessage = SyncMessageEnvelope & RequestMessageContents
154
- // Inline definitions to get good docs, but check the types line up
155
- type _check_request_message = static_assert<RequestMessage extends SyncMessageEnvelope & RequestMessageContents ? true : false>
156
- // We inline the definitions here rather than using the above type alias because
157
- // otherwise typedoc can't produce nice docs without exporting SyncMessageEnvelope
158
- // and RequestMessageContents
159
68
  /** Sent by a {@link Repo} to request a document from a peer
160
69
  *
161
70
  * @remarks
@@ -163,58 +72,86 @@ type _check_request_message = static_assert<RequestMessage extends SyncMessageEn
163
72
  * as the initial sync message when asking the other peer if it has the document.
164
73
  * */
165
74
  export type RequestMessage = {
166
- /** The peer who sent this message */
167
- senderId: PeerId
168
75
  type: "request"
76
+
77
+ /** The peer ID of the sender of this message */
78
+ senderId: PeerId
79
+
80
+ /** The peer ID of the recipient of this message */
81
+ targetId: PeerId
82
+
169
83
  /** The initial automerge sync message */
170
84
  data: Uint8Array
171
- /** The peer this message is for */
172
- targetId: PeerId
85
+
173
86
  /** The document ID this message requests */
174
87
  documentId: DocumentId
175
88
  }
176
89
 
177
- export type MessageContents =
178
- | SyncMessageContents
179
- | EphemeralMessageContents
180
- | RequestMessageContents
181
- | DocumentUnavailableMessageContents
182
-
183
- /** The type of messages that {@link Repo} sends and receive to {@link NetworkAdapter}s */
184
- export type Message =
185
- | SyncMessage
186
- | EphemeralMessage
187
- | RequestMessage
188
- | DocumentUnavailableMessage
189
-
190
- export type SynchronizerMessage =
191
- | SyncMessage
192
- | RequestMessage
193
- | DocumentUnavailableMessage
194
- | EphemeralMessage
195
-
196
-
197
90
  /** Notify the network that we have arrived so everyone knows our peer ID */
198
91
  export type ArriveMessage = {
199
- /** Our peer ID */
200
- senderId: PeerId
201
92
  type: "arrive"
93
+
94
+ /** The peer ID of the sender of this message */
95
+ senderId: PeerId
96
+
97
+ /** Arrive messages don't have a targetId */
98
+ targetId: never
202
99
  }
203
100
 
204
101
  /** Respond to an arriving peer with our peer ID */
205
102
  export type WelcomeMessage = {
206
- /** Our peer ID */
103
+ type: "welcome"
104
+
105
+ /** The peer ID of the recipient sender this message */
207
106
  senderId: PeerId
208
- /** The ID of the peer who sent the {@link ArriveMessage} we are responding to */
107
+
108
+ /** The peer ID of the recipient of this message */
209
109
  targetId: PeerId
210
- type: "welcome"
211
110
  }
212
111
 
213
- /** The type of messages that {@link NetworkAdapter}s send and receive to each other
112
+ /** These are message types that a {@link NetworkAdapter} surfaces to a {@link Repo}. */
113
+ export type RepoMessage =
114
+ | SyncMessage
115
+ | EphemeralMessage
116
+ | RequestMessage
117
+ | DocumentUnavailableMessage
118
+
119
+ /** These are all the message types that a {@link NetworkAdapter} might see.
214
120
  *
215
121
  * @remarks
216
- * It is not _required_ that a {@link NetworkAdapter} use this message type.
217
- * NetworkAdapters are free to use whatever message type makes sense for their
218
- * transport. However, this type is a useful default.
122
+ * It is not _required_ that a {@link NetworkAdapter} use these types: They are free to use
123
+ * whatever message type makes sense for their transport. However, this type is a useful default.
219
124
  * */
220
- export type NetworkAdapterMessage = ArriveMessage | WelcomeMessage | Message
125
+ export type Message = RepoMessage | ArriveMessage | WelcomeMessage
126
+
127
+ /**
128
+ * The contents of a message, without the sender ID or other properties added by the {@link NetworkSubsystem})
129
+ */
130
+ export type MessageContents<T extends Message = Message> =
131
+ T extends EphemeralMessage
132
+ ? Omit<T, "senderId" | "count" | "sessionId">
133
+ : Omit<T, "senderId">
134
+
135
+ // TYPE GUARDS
136
+
137
+ export const isValidRepoMessage = (message: Message): message is RepoMessage =>
138
+ typeof message === "object" &&
139
+ typeof message.type === "string" &&
140
+ typeof message.senderId === "string" &&
141
+ (isSyncMessage(message) ||
142
+ isEphemeralMessage(message) ||
143
+ isRequestMessage(message) ||
144
+ isDocumentUnavailableMessage(message))
145
+
146
+ // prettier-ignore
147
+ export const isDocumentUnavailableMessage = (msg: Message): msg is DocumentUnavailableMessage =>
148
+ msg.type === "doc-unavailable"
149
+
150
+ export const isRequestMessage = (msg: Message): msg is RequestMessage =>
151
+ msg.type === "request"
152
+
153
+ export const isSyncMessage = (msg: Message): msg is SyncMessage =>
154
+ msg.type === "sync"
155
+
156
+ export const isEphemeralMessage = (msg: Message): msg is EphemeralMessage =>
157
+ msg.type === "ephemeral"
@@ -24,8 +24,8 @@ function keyHash(binary: Uint8Array) {
24
24
  }
25
25
 
26
26
  function headsHash(heads: A.Heads): string {
27
- let encoder = new TextEncoder()
28
- let headsbinary = mergeArrays(heads.map((h: string) => encoder.encode(h)))
27
+ const encoder = new TextEncoder()
28
+ const headsbinary = mergeArrays(heads.map((h: string) => encoder.encode(h)))
29
29
  return keyHash(headsbinary)
30
30
  }
31
31
 
@@ -53,7 +53,7 @@ export class StorageSubsystem {
53
53
  if (!this.#chunkInfos.has(documentId)) {
54
54
  this.#chunkInfos.set(documentId, [])
55
55
  }
56
- this.#chunkInfos.get(documentId)!!.push({
56
+ this.#chunkInfos.get(documentId)!.push({
57
57
  key,
58
58
  type: "incremental",
59
59
  size: binary.length,
@@ -122,18 +122,18 @@ export class StorageSubsystem {
122
122
  if (!this.#shouldSave(documentId, doc)) {
123
123
  return
124
124
  }
125
- let sourceChunks = this.#chunkInfos.get(documentId) ?? []
125
+ const sourceChunks = this.#chunkInfos.get(documentId) ?? []
126
126
  if (this.#shouldCompact(sourceChunks)) {
127
- this.#saveTotal(documentId, doc, sourceChunks)
127
+ void this.#saveTotal(documentId, doc, sourceChunks)
128
128
  } else {
129
- this.#saveIncremental(documentId, doc)
129
+ void this.#saveIncremental(documentId, doc)
130
130
  }
131
131
  this.#storedHeads.set(documentId, A.getHeads(doc))
132
132
  }
133
133
 
134
134
  async remove(documentId: DocumentId) {
135
- this.#storageAdapter.removeRange([documentId, "snapshot"])
136
- this.#storageAdapter.removeRange([documentId, "incremental"])
135
+ void this.#storageAdapter.removeRange([documentId, "snapshot"])
136
+ void this.#storageAdapter.removeRange([documentId, "incremental"])
137
137
  }
138
138
 
139
139
  #shouldSave(documentId: DocumentId, doc: A.Doc<unknown>): boolean {
@@ -1,21 +1,12 @@
1
- import { Repo } from "../Repo.js"
2
1
  import { DocHandle } from "../DocHandle.js"
3
- import {
4
- documentIdToBinary,
5
- binaryToDocumentId,
6
- stringifyAutomergeUrl,
7
- } from "../DocUrl.js"
8
- import { PeerId, DocumentId } from "../types.js"
2
+ import { stringifyAutomergeUrl } from "../DocUrl.js"
3
+ import { Repo } from "../Repo.js"
4
+ import { DocumentId, PeerId } from "../types.js"
9
5
  import { DocSynchronizer } from "./DocSynchronizer.js"
10
6
  import { Synchronizer } from "./Synchronizer.js"
11
7
 
12
8
  import debug from "debug"
13
- import {
14
- DocumentUnavailableMessage,
15
- RequestMessage,
16
- SynchronizerMessage,
17
- SyncMessage,
18
- } from "../network/messages.js"
9
+ import { RepoMessage } from "../network/messages.js"
19
10
  const log = debug("automerge-repo:collectionsync")
20
11
 
21
12
  /** A CollectionSynchronizer is responsible for synchronizing a DocCollection with peers. */
@@ -66,7 +57,7 @@ export class CollectionSynchronizer extends Synchronizer {
66
57
  * When we receive a sync message for a document we haven't got in memory, we
67
58
  * register it with the repo and start synchronizing
68
59
  */
69
- async receiveMessage(message: SynchronizerMessage) {
60
+ async receiveMessage(message: RepoMessage) {
70
61
  log(
71
62
  `onSyncMessage: ${message.senderId}, ${message.documentId}, ${
72
63
  "data" in message ? message.data.byteLength + "bytes" : ""
@@ -121,7 +112,7 @@ export class CollectionSynchronizer extends Synchronizer {
121
112
  this.#peers.add(peerId)
122
113
  for (const docSynchronizer of Object.values(this.#docSynchronizers)) {
123
114
  const { documentId } = docSynchronizer
124
- this.repo.sharePolicy(peerId, documentId).then(okToShare => {
115
+ void this.repo.sharePolicy(peerId, documentId).then(okToShare => {
125
116
  if (okToShare) docSynchronizer.beginSync([peerId])
126
117
  })
127
118
  }