@automerge/automerge-repo 2.5.0 → 2.5.2-alpha.0

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.
@@ -14,6 +14,7 @@ export class CollectionSynchronizer extends Synchronizer {
14
14
  /** Used to determine if the document is know to the Collection and a synchronizer exists or is being set up */
15
15
  #docSetUp = {};
16
16
  #denylist;
17
+ #hasRequested = new Map();
17
18
  constructor(repo, denylist = []) {
18
19
  super();
19
20
  this.repo = repo;
@@ -83,6 +84,15 @@ export class CollectionSynchronizer extends Synchronizer {
83
84
  });
84
85
  return;
85
86
  }
87
+ // Record the request so that even if access is denied now, we know that the
88
+ // peer requested the document so that if the share policy changes we know
89
+ // to begin syncing with this peer
90
+ if (message.type === "request") {
91
+ if (!this.#hasRequested.has(documentId)) {
92
+ this.#hasRequested.set(documentId, new Set());
93
+ }
94
+ this.#hasRequested.get(documentId)?.add(message.senderId);
95
+ }
86
96
  const hasAccess = await this.repo.shareConfig.access(message.senderId, documentId);
87
97
  if (!hasAccess) {
88
98
  log("access denied");
@@ -111,6 +121,7 @@ export class CollectionSynchronizer extends Synchronizer {
111
121
  if (this.#docSetUp[handle.documentId]) {
112
122
  return;
113
123
  }
124
+ this.#docSetUp[handle.documentId] = true;
114
125
  const docSynchronizer = this.#fetchDocSynchronizer(handle);
115
126
  void this.#documentGenerousPeers(handle.documentId).then(peers => {
116
127
  void docSynchronizer.beginSync(peers);
@@ -145,6 +156,9 @@ export class CollectionSynchronizer extends Synchronizer {
145
156
  removePeer(peerId) {
146
157
  log(`removing peer ${peerId}`);
147
158
  this.#peers.delete(peerId);
159
+ for (const requested of this.#hasRequested.values()) {
160
+ requested.delete(peerId);
161
+ }
148
162
  for (const docSynchronizer of Object.values(this.docSynchronizers)) {
149
163
  docSynchronizer.endSync(peerId);
150
164
  }
@@ -153,6 +167,38 @@ export class CollectionSynchronizer extends Synchronizer {
153
167
  get peers() {
154
168
  return Array.from(this.#peers);
155
169
  }
170
+ /**
171
+ * Re-evaluates share policy for a document and updates sync accordingly
172
+ *
173
+ * @remarks
174
+ * This is called when the share policy for a document has changed. It re-evaluates
175
+ * which peers should have access and starts/stops synchronization as needed.
176
+ */
177
+ async reevaluateDocumentShare() {
178
+ const peers = Array.from(this.#peers);
179
+ const docPromises = [];
180
+ for (const docSynchronizer of Object.values(this.docSynchronizers)) {
181
+ const documentId = docSynchronizer.documentId;
182
+ docPromises.push((async () => {
183
+ for (const peerId of peers) {
184
+ const shouldShare = await this.#shouldShare(peerId, documentId);
185
+ const isAlreadySyncing = docSynchronizer.hasPeer(peerId);
186
+ log(`reevaluateDocumentShare: ${peerId} for ${documentId}, shouldShare: ${shouldShare}, isAlreadySyncing: ${isAlreadySyncing}`);
187
+ if (shouldShare && !isAlreadySyncing) {
188
+ log(`reevaluateDocumentShare: starting sync with ${peerId} for ${documentId}`);
189
+ void docSynchronizer.beginSync([peerId]);
190
+ }
191
+ else if (!shouldShare && isAlreadySyncing) {
192
+ log(`reevaluateDocumentShare: stopping sync with ${peerId} for ${documentId}`);
193
+ docSynchronizer.endSync(peerId);
194
+ }
195
+ }
196
+ })().catch(e => {
197
+ console.log(`error reevaluating document share for ${documentId}: ${e}`);
198
+ }));
199
+ }
200
+ await Promise.allSettled(docPromises);
201
+ }
156
202
  metrics() {
157
203
  return Object.fromEntries(Object.entries(this.docSynchronizers).map(([documentId, synchronizer]) => {
158
204
  return [documentId, synchronizer.metrics()];
@@ -163,6 +209,7 @@ export class CollectionSynchronizer extends Synchronizer {
163
209
  this.repo.shareConfig.announce(peerId, documentId),
164
210
  this.repo.shareConfig.access(peerId, documentId),
165
211
  ]);
166
- return announce && access;
212
+ const hasRequested = this.#hasRequested.get(documentId)?.has(peerId) ?? false;
213
+ return announce || (access && hasRequested);
167
214
  }
168
215
  }
@@ -130,8 +130,8 @@ export class DocSynchronizer extends Synchronizer {
130
130
  durationMillis: end - start,
131
131
  forPeer: peerId,
132
132
  });
133
+ this.#setSyncState(peerId, newSyncState);
133
134
  if (message) {
134
- this.#setSyncState(peerId, newSyncState);
135
135
  const isNew = A.getHeads(doc).length === 0;
136
136
  if (!this.#handle.isReady() &&
137
137
  isNew &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "2.5.0",
3
+ "version": "2.5.2-alpha.0",
4
4
  "description": "A repository object to manage a collection of automerge documents",
5
5
  "repository": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo",
6
6
  "author": "Peter van Hardenberg <pvh@pvh.ca>",
@@ -59,5 +59,5 @@
59
59
  "publishConfig": {
60
60
  "access": "public"
61
61
  },
62
- "gitHead": "fffb5789bfc7a18b3d9f1e668395c7c465e34be1"
62
+ "gitHead": "ba4493efcd7819fe841d3647f28090837792d964"
63
63
  }