@automerge/automerge-repo 2.0.3 → 2.0.5

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.
@@ -153,9 +153,14 @@ export declare class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
153
153
  * Called by the repo when a doc handle changes or we receive new remote heads.
154
154
  * @hidden
155
155
  */
156
- setRemoteHeads(storageId: StorageId, heads: UrlHeads): void;
157
- /** Returns the heads of the storageId. */
156
+ setSyncInfo(storageId: StorageId, syncInfo: SyncInfo): void;
157
+ /** Returns the heads of the storageId.
158
+ *
159
+ * @deprecated Use getSyncInfo instead.
160
+ */
158
161
  getRemoteHeads(storageId: StorageId): UrlHeads | undefined;
162
+ /** Returns the heads and the timestamp of the last update for the storageId. */
163
+ getSyncInfo(storageId: StorageId): SyncInfo | undefined;
159
164
  /**
160
165
  * All changes to an Automerge document should be made through this method.
161
166
  * Inside the callback, the document should be treated as mutable: all edits will be recorded
@@ -218,6 +223,10 @@ export declare class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
218
223
  numChanges: number;
219
224
  };
220
225
  }
226
+ export type SyncInfo = {
227
+ lastHeads: UrlHeads;
228
+ lastSyncTimestamp: number;
229
+ };
221
230
  /** @hidden */
222
231
  export type DocHandleOptions<T> = {
223
232
  /** If we know this is a new document (because we're creating it) this should be set to true. */
@@ -278,6 +287,7 @@ export interface DocHandleOutboundEphemeralMessagePayload<T> {
278
287
  export interface DocHandleRemoteHeadsPayload {
279
288
  storageId: StorageId;
280
289
  heads: UrlHeads;
290
+ timestamp: number;
281
291
  }
282
292
  /**
283
293
  * Possible internal states for a DocHandle
@@ -1 +1 @@
1
- {"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"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"}
package/dist/DocHandle.js CHANGED
@@ -31,8 +31,8 @@ export class DocHandle extends EventEmitter {
31
31
  /** How long to wait before giving up on a document. (Note that a document will be marked
32
32
  * unavailable much sooner if all known peers respond that they don't have it.) */
33
33
  #timeoutDelay = 60_000;
34
- /** A dictionary mapping each peer to the last heads we know they have. */
35
- #remoteHeads = {};
34
+ /** A dictionary mapping each peer to the last known heads we have. */
35
+ #syncInfoByStorageId = {};
36
36
  /** Cache for view handles, keyed by the stringified heads */
37
37
  #viewCache = new Map();
38
38
  /** @hidden */
@@ -403,13 +403,24 @@ export class DocHandle extends EventEmitter {
403
403
  * Called by the repo when a doc handle changes or we receive new remote heads.
404
404
  * @hidden
405
405
  */
406
- setRemoteHeads(storageId, heads) {
407
- this.#remoteHeads[storageId] = heads;
408
- this.emit("remote-heads", { storageId, heads });
406
+ setSyncInfo(storageId, syncInfo) {
407
+ this.#syncInfoByStorageId[storageId] = syncInfo;
408
+ this.emit("remote-heads", {
409
+ storageId,
410
+ heads: syncInfo.lastHeads,
411
+ timestamp: syncInfo.lastSyncTimestamp,
412
+ });
409
413
  }
410
- /** Returns the heads of the storageId. */
414
+ /** Returns the heads of the storageId.
415
+ *
416
+ * @deprecated Use getSyncInfo instead.
417
+ */
411
418
  getRemoteHeads(storageId) {
412
- return this.#remoteHeads[storageId];
419
+ return this.#syncInfoByStorageId[storageId]?.lastHeads;
420
+ }
421
+ /** Returns the heads and the timestamp of the last update for the storageId. */
422
+ getSyncInfo(storageId) {
423
+ return this.#syncInfoByStorageId[storageId];
413
424
  }
414
425
  /**
415
426
  * All changes to an Automerge document should be made through this method.
@@ -1 +1 @@
1
- {"version":3,"file":"RemoteHeadsSubscriptions.d.ts","sourceRoot":"","sources":["../src/RemoteHeadsSubscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EACL,kBAAkB,EAClB,gCAAgC,EACjC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAItC,MAAM,MAAM,mCAAmC,GAAG;IAChD,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,QAAQ,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAGD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,QAAQ,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,6BAA6B,GAAG;IACnC,sBAAsB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,IAAI,CAAA;IAC9E,oBAAoB,EAAE,CAAC,OAAO,EAAE;QAC9B,KAAK,EAAE,MAAM,EAAE,CAAA;QACf,GAAG,CAAC,EAAE,SAAS,EAAE,CAAA;QACjB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;KACrB,KAAK,IAAI,CAAA;IACV,qBAAqB,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAA;CACnE,CAAA;AAED,qBAAa,wBAAyB,SAAQ,YAAY,CAAC,6BAA6B,CAAC;;IAcvF,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE;IAkBvC,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE;IAsB3C,oBAAoB,CAAC,OAAO,EAAE,gCAAgC;IA0E9D,sEAAsE;IACtE,iBAAiB,CAAC,GAAG,EAAE,kBAAkB;IAgDzC,kEAAkE;IAClE,iCAAiC,CAC/B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,QAAQ;IAgCjB,eAAe,CAAC,MAAM,EAAE,MAAM;IAwB9B,UAAU,CAAC,MAAM,EAAE,MAAM;IA2BzB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;CAuE1D"}
1
+ {"version":3,"file":"RemoteHeadsSubscriptions.d.ts","sourceRoot":"","sources":["../src/RemoteHeadsSubscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EACL,kBAAkB,EAClB,gCAAgC,EACjC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAKtC,MAAM,MAAM,mCAAmC,GAAG;IAChD,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,QAAQ,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAGD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,QAAQ,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,6BAA6B,GAAG;IACnC,sBAAsB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,IAAI,CAAA;IAC9E,oBAAoB,EAAE,CAAC,OAAO,EAAE;QAC9B,KAAK,EAAE,MAAM,EAAE,CAAA;QACf,GAAG,CAAC,EAAE,SAAS,EAAE,CAAA;QACjB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;KACrB,KAAK,IAAI,CAAA;IACV,qBAAqB,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAA;CACnE,CAAA;AAED,qBAAa,wBAAyB,SAAQ,YAAY,CAAC,6BAA6B,CAAC;;IAcvF,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE;IAkBvC,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE;IAsB3C,oBAAoB,CAAC,OAAO,EAAE,gCAAgC;IA0E9D,sEAAsE;IACtE,iBAAiB,CAAC,GAAG,EAAE,kBAAkB;IAgDzC,kEAAkE;IAClE,iCAAiC,CAC/B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,QAAQ;IAqCjB,eAAe,CAAC,MAAM,EAAE,MAAM;IAwB9B,UAAU,CAAC,MAAM,EAAE,MAAM;IA2BzB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;CAuE1D"}
@@ -1,8 +1,8 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import debug from "debug";
3
3
  export class RemoteHeadsSubscriptions extends EventEmitter {
4
- // Storage IDs we have received remote heads from
5
- #knownHeads = new Map();
4
+ // Last known heads and timestamp for each storageId that we know about
5
+ #syncInfoByDocId = new Map();
6
6
  // Storage IDs we have subscribed to via Repo.subscribeToRemoteHeads
7
7
  #ourSubscriptions = new Set();
8
8
  // Storage IDs other peers have subscribed to by sending us a control message
@@ -91,17 +91,17 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
91
91
  const subscribedDocs = this.#subscribedDocsByPeer.get(control.senderId);
92
92
  if (subscribedDocs) {
93
93
  for (const documentId of subscribedDocs) {
94
- const knownHeads = this.#knownHeads.get(documentId);
95
- if (!knownHeads) {
94
+ const syncInfo = this.#syncInfoByDocId.get(documentId);
95
+ if (!syncInfo) {
96
96
  continue;
97
97
  }
98
- const lastHeads = knownHeads.get(remote);
99
- if (lastHeads) {
98
+ const syncInfoForRemote = syncInfo.get(remote);
99
+ if (syncInfoForRemote) {
100
100
  this.emit("notify-remote-heads", {
101
101
  targetId: control.senderId,
102
102
  documentId,
103
- heads: lastHeads.heads,
104
- timestamp: lastHeads.timestamp,
103
+ heads: syncInfoForRemote.lastHeads,
104
+ timestamp: syncInfoForRemote.lastSyncTimestamp,
105
105
  storageId: remote,
106
106
  });
107
107
  }
@@ -156,15 +156,20 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
156
156
  /** A peer we are directly connected to has updated their heads */
157
157
  handleImmediateRemoteHeadsChanged(documentId, storageId, heads) {
158
158
  this.#log("handleLocalHeadsChanged", documentId, storageId, heads);
159
- const remote = this.#knownHeads.get(documentId);
159
+ const remote = this.#syncInfoByDocId.get(documentId);
160
160
  const timestamp = Date.now();
161
161
  if (!remote) {
162
- this.#knownHeads.set(documentId, new Map([[storageId, { heads, timestamp }]]));
162
+ this.#syncInfoByDocId.set(documentId, new Map([
163
+ [storageId, { lastSyncTimestamp: timestamp, lastHeads: heads }],
164
+ ]));
163
165
  }
164
166
  else {
165
167
  const docRemote = remote.get(storageId);
166
- if (!docRemote || docRemote.timestamp < Date.now()) {
167
- remote.set(storageId, { heads, timestamp: Date.now() });
168
+ if (!docRemote || docRemote.lastSyncTimestamp < Date.now()) {
169
+ remote.set(storageId, {
170
+ lastSyncTimestamp: Date.now(),
171
+ lastHeads: heads,
172
+ });
168
173
  }
169
174
  }
170
175
  const theirSubs = this.#theirSubscriptions.get(storageId);
@@ -191,13 +196,13 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
191
196
  peers: [peerId],
192
197
  });
193
198
  }
194
- for (const [documentId, remote] of this.#knownHeads) {
195
- for (const [storageId, { heads, timestamp }] of remote) {
199
+ for (const [documentId, remote] of this.#syncInfoByDocId) {
200
+ for (const [storageId, { lastHeads, lastSyncTimestamp }] of remote) {
196
201
  this.emit("notify-remote-heads", {
197
202
  targetId: peerId,
198
203
  documentId: documentId,
199
- heads: heads,
200
- timestamp: timestamp,
204
+ heads: lastHeads,
205
+ timestamp: lastSyncTimestamp,
201
206
  storageId: storageId,
202
207
  });
203
208
  }
@@ -231,7 +236,7 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
231
236
  this.#subscribedDocsByPeer.set(peerId, subscribedDocs);
232
237
  }
233
238
  subscribedDocs.add(documentId);
234
- const remoteHeads = this.#knownHeads.get(documentId);
239
+ const remoteHeads = this.#syncInfoByDocId.get(documentId);
235
240
  if (remoteHeads) {
236
241
  for (const [storageId, lastHeads] of remoteHeads) {
237
242
  const subscribedPeers = this.#theirSubscriptions.get(storageId);
@@ -239,8 +244,8 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
239
244
  this.emit("notify-remote-heads", {
240
245
  targetId: peerId,
241
246
  documentId,
242
- heads: lastHeads.heads,
243
- timestamp: lastHeads.timestamp,
247
+ heads: lastHeads.lastHeads,
248
+ timestamp: lastHeads.lastSyncTimestamp,
244
249
  storageId,
245
250
  });
246
251
  }
@@ -260,19 +265,19 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
260
265
  !this.#theirSubscriptions.has(storageId)) {
261
266
  continue;
262
267
  }
263
- let remote = this.#knownHeads.get(documentId);
268
+ let remote = this.#syncInfoByDocId.get(documentId);
264
269
  if (!remote) {
265
270
  remote = new Map();
266
- this.#knownHeads.set(documentId, remote);
271
+ this.#syncInfoByDocId.set(documentId, remote);
267
272
  }
268
273
  const docRemote = remote.get(storageId);
269
- if (docRemote && docRemote.timestamp >= timestamp) {
274
+ if (docRemote && docRemote.lastSyncTimestamp >= timestamp) {
270
275
  continue;
271
276
  }
272
277
  else {
273
278
  remote.set(storageId, {
274
- timestamp,
275
- heads: heads,
279
+ lastSyncTimestamp: timestamp,
280
+ lastHeads: heads,
276
281
  });
277
282
  changedHeads.push({
278
283
  documentId,
@@ -1 +1 @@
1
- {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAQ5C,OAAO,EAEL,SAAS,EAKV,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EACL,uBAAuB,EACvB,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAA;AACjF,OAAO,EACL,cAAc,EAEf,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,MAAM,EACP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAa,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG;IACzD,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;IAChE,IAAI,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IAC3B,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;CACzE,CAAA;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IAC3B,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;IACxE,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;CACjE,CAAA;AAMD,8FAA8F;AAC9F;;;;;;GAMG;AACH,qBAAa,IAAK,SAAQ,YAAY,CAAC,UAAU,CAAC;;IAGhD,cAAc;IACd,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,cAAc;IACd,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC,mDAAmD;IACnD,cAAc;IACd,gBAAgB,SAAM;IAItB,cAAc;IACd,YAAY,EAAE,sBAAsB,CAAA;IAEpC,sDAAsD;IACtD,cAAc;IACd,WAAW,EAAE,WAAW,CAAmB;IAE3C,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAM3C,EACV,OAAO,EACP,OAAY,EACZ,MAAuB,EACvB,WAAW,EACX,WAAmC,EACnC,0BAAkC,EAClC,QAAa,GACd,GAAE,UAAe;IAyPlB,8CAA8C;IAC9C,IAAI,OAAO,uCAEV;IAED,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIzD;;;;OAIG;IACH,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAuBzC;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAmBnC,gBAAgB,CAAC,CAAC,EAChB,EAAE,EAAE,aAAa,EACjB,OAAO,GAAE,YAAiB,GACzB,uBAAuB,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAgKzC,IAAI,CAAC,CAAC,EACV,EAAE,EAAE,aAAa,EACjB,OAAO,GAAE,eAAe,GAAG,YAAiB,GAC3C,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAoExB;;;OAGG;IACG,WAAW,CAAC,CAAC;IACjB,sDAAsD;IACtD,EAAE,EAAE,aAAa,EACjB,OAAO,GAAE,eAAe,GAAG,YAAiB,GAC3C,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAmBxB,MAAM;IACJ,oDAAoD;IACpD,EAAE,EAAE,aAAa;IAYnB;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAQhE;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU;IAY5B,kBAAkB,GAAI,SAAS,SAAS,EAAE,UASzC;IAED,SAAS,QAAa,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAMnD;IAED;;;;;OAKG;IACG,KAAK,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAcpD;;;;;OAKG;IACG,eAAe,CAAC,UAAU,EAAE,UAAU;IA6B5C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,OAAO,IAAI;QAAE,SAAS,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAA;KAAE;CAGjD;AAED,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;8DAC0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB,gDAAgD;IAChD,OAAO,CAAC,EAAE,uBAAuB,CAAA;IAEjC,iEAAiE;IACjE,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAA;IAEnC;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IAEzB;;OAEG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAA;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAA;CAC1B;AAED;;;;;;;KAOK;AACL,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,KACpB,OAAO,CAAC,OAAO,CAAC,CAAA;AAGrB,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;IACxC,6BAA6B;IAC7B,iBAAiB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IACvD,4FAA4F;IAC5F,sBAAsB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAA;CACzC;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,MAAM,MAAM,UAAU,GAClB,cAAc,GACd;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GACD;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA"}
1
+ {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
package/dist/Repo.js CHANGED
@@ -118,12 +118,15 @@ export class Repo extends EventEmitter {
118
118
  if (!storageId) {
119
119
  return;
120
120
  }
121
- const heads = handle.getRemoteHeads(storageId);
121
+ const heads = handle.getSyncInfo(storageId)?.lastHeads;
122
122
  const haveHeadsChanged = message.syncState.theirHeads &&
123
123
  (!heads ||
124
124
  !headsAreSame(heads, encodeHeads(message.syncState.theirHeads)));
125
125
  if (haveHeadsChanged && message.syncState.theirHeads) {
126
- handle.setRemoteHeads(storageId, encodeHeads(message.syncState.theirHeads));
126
+ handle.setSyncInfo(storageId, {
127
+ lastHeads: encodeHeads(message.syncState.theirHeads),
128
+ lastSyncTimestamp: Date.now(),
129
+ });
127
130
  if (storageId && this.#remoteHeadsGossipingEnabled) {
128
131
  this.#remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(message.documentId, storageId, encodeHeads(message.syncState.theirHeads));
129
132
  }
@@ -154,9 +157,12 @@ export class Repo extends EventEmitter {
154
157
  });
155
158
  }
156
159
  });
157
- this.#remoteHeadsSubscriptions.on("remote-heads-changed", message => {
158
- const handle = this.#handleCache[message.documentId];
159
- handle.setRemoteHeads(message.storageId, message.remoteHeads);
160
+ this.#remoteHeadsSubscriptions.on("remote-heads-changed", ({ documentId, storageId, remoteHeads, timestamp }) => {
161
+ const handle = this.#handleCache[documentId];
162
+ handle.setSyncInfo(storageId, {
163
+ lastHeads: remoteHeads,
164
+ lastSyncTimestamp: timestamp,
165
+ });
160
166
  });
161
167
  }
162
168
  }
@@ -449,6 +455,10 @@ export class Repo extends EventEmitter {
449
455
  }
450
456
  // If the handle isn't ready, wait for it and then return it
451
457
  await progress.handle.whenReady([READY, UNAVAILABLE]);
458
+ if (progress.handle.state === "unavailable" &&
459
+ !allowableStates.includes(UNAVAILABLE)) {
460
+ throw new Error(`Document ${id} is unavailable`);
461
+ }
452
462
  return progress.handle;
453
463
  }
454
464
  }
package/dist/index.d.ts CHANGED
@@ -36,7 +36,7 @@ export type { StorageAdapterInterface } from "./storage/StorageAdapterInterface.
36
36
  import { next as Automerge } from "@automerge/automerge/slim";
37
37
  /** @hidden **/
38
38
  export * as cbor from "./helpers/cbor.js";
39
- export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedChangePayload, DocHandleEphemeralMessagePayload, DocHandleRemoteHeadsPayload, DocHandleEvents, DocHandleOptions, DocHandleOutboundEphemeralMessagePayload, HandleState, } from "./DocHandle.js";
39
+ export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedChangePayload, DocHandleEphemeralMessagePayload, DocHandleRemoteHeadsPayload, DocHandleEvents, DocHandleOptions, DocHandleOutboundEphemeralMessagePayload, HandleState, SyncInfo, } from "./DocHandle.js";
40
40
  export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
41
41
  export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, PeerMetadata, } from "./network/NetworkAdapterInterface.js";
42
42
  export type { NetworkSubsystemEvents, PeerPayload, } from "./network/NetworkSubsystem.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAGrD,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,WAAW,EAEZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;CACvE;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAyBV,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyBtE,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IAqID,OAAO,CAAC,MAAM,EAAE,MAAM;IAIhB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA8DjC,OAAO,CAAC,MAAM,EAAE,MAAM;IAKtB,cAAc,CAAC,OAAO,EAAE,WAAW;IAkBnC,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;IAuBjD,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;IAwFxD,OAAO,IAAI;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;CAM7E"}
1
+ {"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAGrD,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,WAAW,EAEZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;CACvE;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAyBV,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyBtE,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IAqID,OAAO,CAAC,MAAM,EAAE,MAAM;IAIhB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA8DjC,OAAO,CAAC,MAAM,EAAE,MAAM;IAOtB,cAAc,CAAC,OAAO,EAAE,WAAW;IAkBnC,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;IAuBjD,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;IA2FxD,OAAO,IAAI;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;CAM7E"}
@@ -209,6 +209,8 @@ export class DocSynchronizer extends Synchronizer {
209
209
  endSync(peerId) {
210
210
  this.#log(`removing peer ${peerId}`);
211
211
  this.#peers = this.#peers.filter(p => p !== peerId);
212
+ delete this.#peerDocumentStatuses[peerId];
213
+ this.#checkDocUnavailable();
212
214
  }
213
215
  receiveMessage(message) {
214
216
  switch (message.type) {
@@ -288,12 +290,15 @@ export class DocSynchronizer extends Synchronizer {
288
290
  #checkDocUnavailable() {
289
291
  // if we know none of the peers have the document, tell all our peers that we don't either
290
292
  if (this.#syncStarted &&
291
- this.#handle.inState([REQUESTING]) &&
293
+ this.#handle.inState([REQUESTING, UNAVAILABLE]) &&
292
294
  this.#peers.every(peerId => this.#peerDocumentStatuses[peerId] === "unavailable" ||
293
295
  this.#peerDocumentStatuses[peerId] === "wants")) {
294
296
  this.#peers
295
297
  .filter(peerId => this.#peerDocumentStatuses[peerId] === "wants")
296
298
  .forEach(peerId => {
299
+ // Transition the peer to unavailable so that we don't send it a doc-unavailable
300
+ // message every time we run #checkDocUnavailable
301
+ this.#peerDocumentStatuses[peerId] = "unavailable";
297
302
  const message = {
298
303
  type: "doc-unavailable",
299
304
  documentId: this.#handle.documentId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
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": "47bbb8af119776522de99771b095b7351f8d3870"
62
+ "gitHead": "9d24ea3db7c1f459fc66ce43b794a9ed4bef1341"
63
63
  }
package/src/DocHandle.ts CHANGED
@@ -42,8 +42,8 @@ export class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
42
42
  * unavailable much sooner if all known peers respond that they don't have it.) */
43
43
  #timeoutDelay = 60_000
44
44
 
45
- /** A dictionary mapping each peer to the last heads we know they have. */
46
- #remoteHeads: Record<StorageId, UrlHeads> = {}
45
+ /** A dictionary mapping each peer to the last known heads we have. */
46
+ #syncInfoByStorageId: Record<StorageId, SyncInfo> = {}
47
47
 
48
48
  /** Cache for view handles, keyed by the stringified heads */
49
49
  #viewCache: Map<string, DocHandle<T>> = new Map()
@@ -482,14 +482,26 @@ export class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
482
482
  * Called by the repo when a doc handle changes or we receive new remote heads.
483
483
  * @hidden
484
484
  */
485
- setRemoteHeads(storageId: StorageId, heads: UrlHeads) {
486
- this.#remoteHeads[storageId] = heads
487
- this.emit("remote-heads", { storageId, heads })
485
+ setSyncInfo(storageId: StorageId, syncInfo: SyncInfo) {
486
+ this.#syncInfoByStorageId[storageId] = syncInfo
487
+ this.emit("remote-heads", {
488
+ storageId,
489
+ heads: syncInfo.lastHeads,
490
+ timestamp: syncInfo.lastSyncTimestamp,
491
+ })
488
492
  }
489
493
 
490
- /** Returns the heads of the storageId. */
494
+ /** Returns the heads of the storageId.
495
+ *
496
+ * @deprecated Use getSyncInfo instead.
497
+ */
491
498
  getRemoteHeads(storageId: StorageId): UrlHeads | undefined {
492
- return this.#remoteHeads[storageId]
499
+ return this.#syncInfoByStorageId[storageId]?.lastHeads
500
+ }
501
+
502
+ /** Returns the heads and the timestamp of the last update for the storageId. */
503
+ getSyncInfo(storageId: StorageId): SyncInfo | undefined {
504
+ return this.#syncInfoByStorageId[storageId]
493
505
  }
494
506
 
495
507
  /**
@@ -642,6 +654,11 @@ export class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
642
654
 
643
655
  // TYPES
644
656
 
657
+ export type SyncInfo = {
658
+ lastHeads: UrlHeads
659
+ lastSyncTimestamp: number
660
+ }
661
+
645
662
  /** @hidden */
646
663
  export type DocHandleOptions<T> =
647
664
  // NEW DOCUMENTS
@@ -722,6 +739,7 @@ export interface DocHandleOutboundEphemeralMessagePayload<T> {
722
739
  export interface DocHandleRemoteHeadsPayload {
723
740
  storageId: StorageId
724
741
  heads: UrlHeads
742
+ timestamp: number
725
743
  }
726
744
 
727
745
  // STATE MACHINE TYPES & CONSTANTS
@@ -6,6 +6,7 @@ import {
6
6
  } from "./network/messages.js"
7
7
  import { StorageId } from "./index.js"
8
8
  import debug from "debug"
9
+ import { SyncInfo } from "./DocHandle.js"
9
10
 
10
11
  // Notify a DocHandle that remote heads have changed
11
12
  export type RemoteHeadsSubscriptionEventPayload = {
@@ -35,8 +36,8 @@ type RemoteHeadsSubscriptionEvents = {
35
36
  }
36
37
 
37
38
  export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscriptionEvents> {
38
- // Storage IDs we have received remote heads from
39
- #knownHeads: Map<DocumentId, Map<StorageId, LastHeads>> = new Map()
39
+ // Last known heads and timestamp for each storageId that we know about
40
+ #syncInfoByDocId: Map<DocumentId, Map<StorageId, SyncInfo>> = new Map()
40
41
  // Storage IDs we have subscribed to via Repo.subscribeToRemoteHeads
41
42
  #ourSubscriptions: Set<StorageId> = new Set()
42
43
  // Storage IDs other peers have subscribed to by sending us a control message
@@ -142,18 +143,18 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
142
143
  const subscribedDocs = this.#subscribedDocsByPeer.get(control.senderId)
143
144
  if (subscribedDocs) {
144
145
  for (const documentId of subscribedDocs) {
145
- const knownHeads = this.#knownHeads.get(documentId)
146
- if (!knownHeads) {
146
+ const syncInfo = this.#syncInfoByDocId.get(documentId)
147
+ if (!syncInfo) {
147
148
  continue
148
149
  }
149
150
 
150
- const lastHeads = knownHeads.get(remote)
151
- if (lastHeads) {
151
+ const syncInfoForRemote = syncInfo.get(remote)
152
+ if (syncInfoForRemote) {
152
153
  this.emit("notify-remote-heads", {
153
154
  targetId: control.senderId,
154
155
  documentId,
155
- heads: lastHeads.heads,
156
- timestamp: lastHeads.timestamp,
156
+ heads: syncInfoForRemote.lastHeads,
157
+ timestamp: syncInfoForRemote.lastSyncTimestamp,
157
158
  storageId: remote,
158
159
  })
159
160
  }
@@ -218,17 +219,22 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
218
219
  heads: UrlHeads
219
220
  ) {
220
221
  this.#log("handleLocalHeadsChanged", documentId, storageId, heads)
221
- const remote = this.#knownHeads.get(documentId)
222
+ const remote = this.#syncInfoByDocId.get(documentId)
222
223
  const timestamp = Date.now()
223
224
  if (!remote) {
224
- this.#knownHeads.set(
225
+ this.#syncInfoByDocId.set(
225
226
  documentId,
226
- new Map([[storageId, { heads, timestamp }]])
227
+ new Map([
228
+ [storageId, { lastSyncTimestamp: timestamp, lastHeads: heads }],
229
+ ])
227
230
  )
228
231
  } else {
229
232
  const docRemote = remote.get(storageId)
230
- if (!docRemote || docRemote.timestamp < Date.now()) {
231
- remote.set(storageId, { heads, timestamp: Date.now() })
233
+ if (!docRemote || docRemote.lastSyncTimestamp < Date.now()) {
234
+ remote.set(storageId, {
235
+ lastSyncTimestamp: Date.now(),
236
+ lastHeads: heads,
237
+ })
232
238
  }
233
239
  }
234
240
  const theirSubs = this.#theirSubscriptions.get(storageId)
@@ -258,13 +264,13 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
258
264
  })
259
265
  }
260
266
 
261
- for (const [documentId, remote] of this.#knownHeads) {
262
- for (const [storageId, { heads, timestamp }] of remote) {
267
+ for (const [documentId, remote] of this.#syncInfoByDocId) {
268
+ for (const [storageId, { lastHeads, lastSyncTimestamp }] of remote) {
263
269
  this.emit("notify-remote-heads", {
264
270
  targetId: peerId,
265
271
  documentId: documentId,
266
- heads: heads,
267
- timestamp: timestamp,
272
+ heads: lastHeads,
273
+ timestamp: lastSyncTimestamp,
268
274
  storageId: storageId,
269
275
  })
270
276
  }
@@ -307,7 +313,7 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
307
313
 
308
314
  subscribedDocs.add(documentId)
309
315
 
310
- const remoteHeads = this.#knownHeads.get(documentId)
316
+ const remoteHeads = this.#syncInfoByDocId.get(documentId)
311
317
  if (remoteHeads) {
312
318
  for (const [storageId, lastHeads] of remoteHeads) {
313
319
  const subscribedPeers = this.#theirSubscriptions.get(storageId)
@@ -315,8 +321,8 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
315
321
  this.emit("notify-remote-heads", {
316
322
  targetId: peerId,
317
323
  documentId,
318
- heads: lastHeads.heads,
319
- timestamp: lastHeads.timestamp,
324
+ heads: lastHeads.lastHeads,
325
+ timestamp: lastHeads.lastSyncTimestamp,
320
326
  storageId,
321
327
  })
322
328
  }
@@ -345,19 +351,19 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
345
351
  ) {
346
352
  continue
347
353
  }
348
- let remote = this.#knownHeads.get(documentId)
354
+ let remote = this.#syncInfoByDocId.get(documentId)
349
355
  if (!remote) {
350
356
  remote = new Map()
351
- this.#knownHeads.set(documentId, remote)
357
+ this.#syncInfoByDocId.set(documentId, remote)
352
358
  }
353
359
 
354
360
  const docRemote = remote.get(storageId as StorageId)
355
- if (docRemote && docRemote.timestamp >= timestamp) {
361
+ if (docRemote && docRemote.lastSyncTimestamp >= timestamp) {
356
362
  continue
357
363
  } else {
358
364
  remote.set(storageId as StorageId, {
359
- timestamp,
360
- heads: heads as UrlHeads,
365
+ lastSyncTimestamp: timestamp,
366
+ lastHeads: heads as UrlHeads,
361
367
  })
362
368
  changedHeads.push({
363
369
  documentId,
@@ -370,8 +376,3 @@ export class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSubscripti
370
376
  return changedHeads
371
377
  }
372
378
  }
373
-
374
- type LastHeads = {
375
- timestamp: number
376
- heads: UrlHeads
377
- }
package/src/Repo.ts CHANGED
@@ -206,17 +206,17 @@ export class Repo extends EventEmitter<RepoEvents> {
206
206
  return
207
207
  }
208
208
 
209
- const heads = handle.getRemoteHeads(storageId)
209
+ const heads = handle.getSyncInfo(storageId)?.lastHeads
210
210
  const haveHeadsChanged =
211
211
  message.syncState.theirHeads &&
212
212
  (!heads ||
213
213
  !headsAreSame(heads, encodeHeads(message.syncState.theirHeads)))
214
214
 
215
215
  if (haveHeadsChanged && message.syncState.theirHeads) {
216
- handle.setRemoteHeads(
217
- storageId,
218
- encodeHeads(message.syncState.theirHeads)
219
- )
216
+ handle.setSyncInfo(storageId, {
217
+ lastHeads: encodeHeads(message.syncState.theirHeads),
218
+ lastSyncTimestamp: Date.now(),
219
+ })
220
220
 
221
221
  if (storageId && this.#remoteHeadsGossipingEnabled) {
222
222
  this.#remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(
@@ -255,10 +255,16 @@ export class Repo extends EventEmitter<RepoEvents> {
255
255
  }
256
256
  })
257
257
 
258
- this.#remoteHeadsSubscriptions.on("remote-heads-changed", message => {
259
- const handle = this.#handleCache[message.documentId]
260
- handle.setRemoteHeads(message.storageId, message.remoteHeads)
261
- })
258
+ this.#remoteHeadsSubscriptions.on(
259
+ "remote-heads-changed",
260
+ ({ documentId, storageId, remoteHeads, timestamp }) => {
261
+ const handle = this.#handleCache[documentId]
262
+ handle.setSyncInfo(storageId, {
263
+ lastHeads: remoteHeads,
264
+ lastSyncTimestamp: timestamp,
265
+ })
266
+ }
267
+ )
262
268
  }
263
269
  }
264
270
 
@@ -624,6 +630,12 @@ export class Repo extends EventEmitter<RepoEvents> {
624
630
  }
625
631
  // If the handle isn't ready, wait for it and then return it
626
632
  await progress.handle.whenReady([READY, UNAVAILABLE])
633
+ if (
634
+ progress.handle.state === "unavailable" &&
635
+ !allowableStates.includes(UNAVAILABLE)
636
+ ) {
637
+ throw new Error(`Document ${id} is unavailable`)
638
+ }
627
639
  return progress.handle
628
640
  }
629
641
  }
package/src/index.ts CHANGED
@@ -60,6 +60,7 @@ export type {
60
60
  DocHandleOptions,
61
61
  DocHandleOutboundEphemeralMessagePayload,
62
62
  HandleState,
63
+ SyncInfo,
63
64
  } from "./DocHandle.js"
64
65
 
65
66
  export type {
@@ -298,6 +298,8 @@ export class DocSynchronizer extends Synchronizer {
298
298
  endSync(peerId: PeerId) {
299
299
  this.#log(`removing peer ${peerId}`)
300
300
  this.#peers = this.#peers.filter(p => p !== peerId)
301
+ delete this.#peerDocumentStatuses[peerId]
302
+ this.#checkDocUnavailable()
301
303
  }
302
304
 
303
305
  receiveMessage(message: RepoMessage) {
@@ -399,7 +401,7 @@ export class DocSynchronizer extends Synchronizer {
399
401
  // if we know none of the peers have the document, tell all our peers that we don't either
400
402
  if (
401
403
  this.#syncStarted &&
402
- this.#handle.inState([REQUESTING]) &&
404
+ this.#handle.inState([REQUESTING, UNAVAILABLE]) &&
403
405
  this.#peers.every(
404
406
  peerId =>
405
407
  this.#peerDocumentStatuses[peerId] === "unavailable" ||
@@ -409,6 +411,9 @@ export class DocSynchronizer extends Synchronizer {
409
411
  this.#peers
410
412
  .filter(peerId => this.#peerDocumentStatuses[peerId] === "wants")
411
413
  .forEach(peerId => {
414
+ // Transition the peer to unavailable so that we don't send it a doc-unavailable
415
+ // message every time we run #checkDocUnavailable
416
+ this.#peerDocumentStatuses[peerId] = "unavailable"
412
417
  const message: MessageContents<DocumentUnavailableMessage> = {
413
418
  type: "doc-unavailable",
414
419
  documentId: this.#handle.documentId,
@@ -3,7 +3,7 @@ import assert from "assert"
3
3
  import { describe, it } from "vitest"
4
4
  import { generateAutomergeUrl, parseAutomergeUrl } from "../src/AutomergeUrl.js"
5
5
  import { RemoteHeadsSubscriptions } from "../src/RemoteHeadsSubscriptions.js"
6
- import { PeerId, StorageId } from "../src/index.js"
6
+ import { PeerId, StorageId, UrlHeads } from "../src/index.js"
7
7
  import {
8
8
  RemoteHeadsChanged,
9
9
  RemoteSubscriptionControlMessage,
@@ -32,7 +32,7 @@ describe("RepoHeadsSubscriptions", () => {
32
32
  newHeads: {
33
33
  [storageB]: {
34
34
  heads: [],
35
- timestamp: Date.now(),
35
+ timestamp: 1000,
36
36
  },
37
37
  },
38
38
  }
@@ -45,7 +45,7 @@ describe("RepoHeadsSubscriptions", () => {
45
45
  newHeads: {
46
46
  [storageB]: {
47
47
  heads: [],
48
- timestamp: Date.now(),
48
+ timestamp: 2000,
49
49
  },
50
50
  },
51
51
  }
@@ -64,7 +64,7 @@ describe("RepoHeadsSubscriptions", () => {
64
64
  newHeads: {
65
65
  [storageB]: {
66
66
  heads: docBHeads,
67
- timestamp: Date.now() + 1,
67
+ timestamp: 3000,
68
68
  },
69
69
  },
70
70
  }
@@ -153,7 +153,7 @@ describe("RepoHeadsSubscriptions", () => {
153
153
  remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(
154
154
  docC,
155
155
  storageB,
156
- []
156
+ [] as UrlHeads
157
157
  )
158
158
 
159
159
  // should forward remote-heads events
@@ -233,7 +233,7 @@ describe("RepoHeadsSubscriptions", () => {
233
233
  remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(
234
234
  docC,
235
235
  storageB,
236
- []
236
+ [] as UrlHeads
237
237
  )
238
238
 
239
239
  // expect peer c to be notified both changes
@@ -279,7 +279,7 @@ describe("RepoHeadsSubscriptions", () => {
279
279
  remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(
280
280
  docC,
281
281
  storageB,
282
- []
282
+ [] as UrlHeads
283
283
  )
284
284
 
285
285
  // expect peer c to be notified both changes
@@ -309,6 +309,7 @@ describe("RepoHeadsSubscriptions", () => {
309
309
  assert.strictEqual(messages[0].storageId, storageB)
310
310
  assert.strictEqual(messages[0].documentId, docB)
311
311
  assert.deepStrictEqual(messages[0].remoteHeads, docBHeads)
312
+ assert.strictEqual(messages[0].timestamp, 3000)
312
313
  })
313
314
 
314
315
  it("should remove subs of disconnected peers", async () => {
package/test/Repo.test.ts CHANGED
@@ -208,6 +208,65 @@ describe("Repo", () => {
208
208
  }).rejects.toThrow(/Document (.*) is unavailable/)
209
209
  })
210
210
 
211
+ it("immediately marks a document as unavailable even if requested multiple times", async () => {
212
+ /**
213
+ * This exercises an issue where the first time a document is requested
214
+ * from some remote and the remote doesn't have the document then it
215
+ * immediately returns an unavailable error, but if the same document is
216
+ * requested again before the remote is restarted then it never sends
217
+ * the unavailable message leading to timeouts on the requesting end
218
+ */
219
+ const alice = new Repo({
220
+ peerId: "alice" as PeerId,
221
+ sharePolicy: async () => false,
222
+ })
223
+ const bob = new Repo({ peerId: "bob" as PeerId })
224
+ const [aliceToBob, bobToAlice] = DummyNetworkAdapter.createConnectedPair()
225
+ alice.networkSubsystem.addNetworkAdapter(aliceToBob)
226
+ bob.networkSubsystem.addNetworkAdapter(bobToAlice)
227
+ aliceToBob.peerCandidate("bob" as PeerId)
228
+ bobToAlice.peerCandidate("alice" as PeerId)
229
+ await Promise.all([
230
+ alice.networkSubsystem.whenReady(),
231
+ bob.networkSubsystem.whenReady(),
232
+ ])
233
+
234
+ await assert.rejects(() =>
235
+ bob.find("automerge:uKK1dJ4vE3E6r27kz5bsFaCykvM" as AutomergeUrl)
236
+ )
237
+ aliceToBob.emit("peer-disconnected", { peerId: "bob" as PeerId })
238
+ bobToAlice.emit("peer-disconnected", { peerId: "alice" as PeerId })
239
+
240
+ const charlie = new Repo({ peerId: "charlie" as PeerId })
241
+ const [charlieToAlice, aliceToCharlie] =
242
+ DummyNetworkAdapter.createConnectedPair()
243
+ charlie.networkSubsystem.addNetworkAdapter(charlieToAlice)
244
+ alice.networkSubsystem.addNetworkAdapter(aliceToCharlie)
245
+ charlieToAlice.peerCandidate("alice" as PeerId)
246
+ aliceToCharlie.peerCandidate("charlie" as PeerId)
247
+ await Promise.all([
248
+ charlie.networkSubsystem.whenReady(),
249
+ alice.networkSubsystem.whenReady(),
250
+ ])
251
+
252
+ await assert.rejects(() =>
253
+ charlie.find("automerge:uKK1dJ4vE3E6r27kz5bsFaCykvM" as AutomergeUrl)
254
+ )
255
+ })
256
+
257
+ it("should not return an unavailable handle on second request", async () => {
258
+ const alice = new Repo({
259
+ peerId: "alice" as PeerId,
260
+ sharePolicy: async () => true,
261
+ })
262
+ await assert.rejects(() =>
263
+ alice.find("automerge:uKK1dJ4vE3E6r27kz5bsFaCykvM" as AutomergeUrl)
264
+ )
265
+ await assert.rejects(() =>
266
+ alice.find("automerge:uKK1dJ4vE3E6r27kz5bsFaCykvM" as AutomergeUrl)
267
+ )
268
+ })
269
+
211
270
  it("doesn't mark a document as unavailable until network adapters are ready", async () => {
212
271
  const { repo, networkAdapter } = setup({ startReady: false })
213
272
  const url = generateAutomergeUrl()
@@ -1267,9 +1326,10 @@ describe("Repo", () => {
1267
1326
  const nextRemoteHeadsPromise = new Promise<{
1268
1327
  storageId: StorageId
1269
1328
  heads: UrlHeads
1329
+ timestamp: number
1270
1330
  }>(resolve => {
1271
- handle.on("remote-heads", ({ storageId, heads }) => {
1272
- resolve({ storageId, heads })
1331
+ handle.on("remote-heads", ({ storageId, heads, timestamp }) => {
1332
+ resolve({ storageId, heads, timestamp })
1273
1333
  })
1274
1334
  })
1275
1335
 
@@ -1289,10 +1349,10 @@ describe("Repo", () => {
1289
1349
  assert.deepStrictEqual(nextRemoteHeads.storageId, charliedStorageId)
1290
1350
  assert.deepStrictEqual(nextRemoteHeads.heads, charlieHandle.heads())
1291
1351
 
1292
- assert.deepStrictEqual(
1293
- handle.getRemoteHeads(charliedStorageId),
1294
- charlieHandle.heads()
1295
- )
1352
+ const syncInfo = handle.getSyncInfo(charliedStorageId)
1353
+
1354
+ assert.deepStrictEqual(syncInfo?.lastHeads, charlieHandle.heads())
1355
+ assert.strictEqual(syncInfo?.lastSyncTimestamp, nextRemoteHeads.timestamp)
1296
1356
 
1297
1357
  teardown()
1298
1358
  })
@@ -9,6 +9,7 @@ import {
9
9
  DocHandleRemoteHeadsPayload,
10
10
  PeerId,
11
11
  Repo,
12
+ UrlHeads,
12
13
  } from "../src/index.js"
13
14
  import { DummyStorageAdapter } from "../src/helpers/DummyStorageAdapter.js"
14
15
  import { collectMessages } from "./helpers/collectMessages.js"
@@ -18,7 +19,7 @@ import { pause } from "../src/helpers/pause.js"
18
19
  describe("DocHandle.remoteHeads", () => {
19
20
  const TEST_ID = parseAutomergeUrl(generateAutomergeUrl()).documentId
20
21
 
21
- it("should allow to listen for remote head changes and manually read remote heads", async () => {
22
+ it("should allow to listen for remote head changes and manually read sync info", async () => {
22
23
  const handle = new DocHandle<TestDoc>(TEST_ID, { isNew: true })
23
24
  const bobRepo = new Repo({
24
25
  peerId: "bob" as PeerId,
@@ -29,7 +30,10 @@ describe("DocHandle.remoteHeads", () => {
29
30
  const bobStorageId = await bobRepo.storageId()
30
31
 
31
32
  const remoteHeadsMessagePromise = eventPromise(handle, "remote-heads")
32
- handle.setRemoteHeads(bobStorageId, [])
33
+ handle.setSyncInfo(bobStorageId, {
34
+ lastHeads: [] as UrlHeads,
35
+ lastSyncTimestamp: 1000,
36
+ })
33
37
 
34
38
  const remoteHeadsMessage = await remoteHeadsMessagePromise
35
39
 
@@ -37,7 +41,13 @@ describe("DocHandle.remoteHeads", () => {
37
41
  assert.deepStrictEqual(remoteHeadsMessage.heads, [])
38
42
 
39
43
  // read remote heads manually
40
- assert.deepStrictEqual(handle.getRemoteHeads(bobStorageId), [])
44
+
45
+ const syncInfo = handle.getSyncInfo(bobStorageId)
46
+
47
+ assert.deepStrictEqual(syncInfo, {
48
+ lastHeads: [] as UrlHeads,
49
+ lastSyncTimestamp: 1000,
50
+ })
41
51
  })
42
52
 
43
53
  describe("multi hop sync", () => {