@automerge/automerge-repo 1.0.18 → 1.1.0-alpha.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.
Files changed (47) hide show
  1. package/dist/DocHandle.d.ts +7 -8
  2. package/dist/DocHandle.d.ts.map +1 -1
  3. package/dist/DocHandle.js +15 -20
  4. package/dist/RemoteHeadsSubscriptions.d.ts +41 -0
  5. package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -0
  6. package/dist/RemoteHeadsSubscriptions.js +224 -0
  7. package/dist/Repo.d.ts +15 -1
  8. package/dist/Repo.d.ts.map +1 -1
  9. package/dist/Repo.js +118 -8
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/network/NetworkAdapter.d.ts +8 -1
  13. package/dist/network/NetworkAdapter.d.ts.map +1 -1
  14. package/dist/network/NetworkAdapter.js +2 -0
  15. package/dist/network/NetworkSubsystem.d.ts +7 -1
  16. package/dist/network/NetworkSubsystem.d.ts.map +1 -1
  17. package/dist/network/NetworkSubsystem.js +11 -4
  18. package/dist/network/messages.d.ts +24 -1
  19. package/dist/network/messages.d.ts.map +1 -1
  20. package/dist/network/messages.js +5 -1
  21. package/dist/storage/StorageSubsystem.d.ts +5 -3
  22. package/dist/storage/StorageSubsystem.d.ts.map +1 -1
  23. package/dist/storage/StorageSubsystem.js +17 -4
  24. package/dist/storage/types.d.ts +4 -0
  25. package/dist/storage/types.d.ts.map +1 -1
  26. package/dist/synchronizer/CollectionSynchronizer.d.ts +2 -2
  27. package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
  28. package/dist/synchronizer/CollectionSynchronizer.js +7 -3
  29. package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
  30. package/dist/synchronizer/DocSynchronizer.js +0 -9
  31. package/package.json +3 -3
  32. package/src/DocHandle.ts +17 -22
  33. package/src/RemoteHeadsSubscriptions.ts +306 -0
  34. package/src/Repo.ts +173 -11
  35. package/src/index.ts +1 -0
  36. package/src/network/NetworkAdapter.ts +12 -1
  37. package/src/network/NetworkSubsystem.ts +24 -11
  38. package/src/network/messages.ts +30 -1
  39. package/src/storage/StorageSubsystem.ts +24 -6
  40. package/src/storage/types.ts +3 -0
  41. package/src/synchronizer/CollectionSynchronizer.ts +10 -5
  42. package/src/synchronizer/DocSynchronizer.ts +0 -12
  43. package/test/DocHandle.test.ts +1 -18
  44. package/test/RemoteHeadsSubscriptions.test.ts +343 -0
  45. package/test/Repo.test.ts +51 -15
  46. package/test/StorageSubsystem.test.ts +28 -6
  47. package/test/remoteHeads.test.ts +135 -0
package/dist/index.d.ts CHANGED
@@ -37,6 +37,6 @@ export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedCh
37
37
  export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
38
38
  export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, } from "./network/NetworkAdapter.js";
39
39
  export type { DocumentUnavailableMessage, EphemeralMessage, Message, RepoMessage, RequestMessage, SyncMessage, } from "./network/messages.js";
40
- export type { Chunk, ChunkInfo, ChunkType, StorageKey, } from "./storage/types.js";
40
+ export type { Chunk, ChunkInfo, ChunkType, StorageKey, StorageId, } from "./storage/types.js";
41
41
  export * from "./types.js";
42
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,eAAe;AACf,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA;AAIzC,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,wCAAwC,EACxC,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,6BAA6B,CAAA;AAEpC,YAAY,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAE9B,YAAY,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,oBAAoB,CAAA;AAE3B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,eAAe;AACf,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA;AAIzC,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,wCAAwC,EACxC,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,6BAA6B,CAAA;AAEpC,YAAY,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAE9B,YAAY,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,GACV,MAAM,oBAAoB,CAAA;AAE3B,cAAc,YAAY,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
3
  import { Message } from "./messages.js";
4
+ import { StorageId } from "../storage/types.js";
4
5
  /** An interface representing some way to connect to other peers
5
6
  *
6
7
  * @remarks
@@ -10,11 +11,15 @@ import { Message } from "./messages.js";
10
11
  */
11
12
  export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
12
13
  peerId?: PeerId;
14
+ storageId?: StorageId;
15
+ isEphemeral: boolean;
13
16
  /** Called by the {@link Repo} to start the connection process
14
17
  *
15
18
  * @argument peerId - the peerId of this repo
19
+ * @argument storageId - the storage id of the peer
20
+ * @argument isEphemeral - weather or not the other end should persist our sync state
16
21
  */
17
- abstract connect(peerId: PeerId): void;
22
+ abstract connect(peerId: PeerId, storageId: StorageId | undefined, isEphemeral: boolean): void;
18
23
  /** Called by the {@link Repo} to send a message to a peer
19
24
  *
20
25
  * @argument message - the message to send
@@ -40,6 +45,8 @@ export interface OpenPayload {
40
45
  }
41
46
  export interface PeerCandidatePayload {
42
47
  peerId: PeerId;
48
+ storageId?: StorageId;
49
+ isEphemeral: boolean;
43
50
  }
44
51
  export interface PeerDisconnectedPayload {
45
52
  peerId: PeerId;
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAEtC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAErC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,IAAI,IAAI;CAC5B;AAID,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAErC,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAA;IAEjB,+DAA+D;IAC/D,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAEzD,2EAA2E;IAC3E,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAE/D,sEAAsE;IACtE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
1
+ {"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,UAAO;IAElB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,WAAW,EAAE,OAAO,GACnB,IAAI;IAEP;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAErC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,IAAI,IAAI;CAC5B;AAID,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAErC,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAA;IAEjB,+DAA+D;IAC/D,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAEzD,2EAA2E;IAC3E,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAE/D,sEAAsE;IACtE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
@@ -8,4 +8,6 @@ import { EventEmitter } from "eventemitter3";
8
8
  */
9
9
  export class NetworkAdapter extends EventEmitter {
10
10
  peerId; // hmmm, maybe not
11
+ storageId;
12
+ isEphemeral = true;
11
13
  }
@@ -2,10 +2,14 @@ import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
3
  import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js";
4
4
  import { MessageContents, RepoMessage } from "./messages.js";
5
+ import { StorageId } from "../storage/types.js";
5
6
  export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
6
7
  #private;
7
8
  peerId: PeerId;
8
- constructor(adapters: NetworkAdapter[], peerId?: PeerId);
9
+ private storageId;
10
+ private isEphemeral;
11
+ constructor(adapters: NetworkAdapter[], peerId: PeerId, storageId: Promise<StorageId | undefined>, // todo: we shouldn't pass a promise here
12
+ isEphemeral: boolean);
9
13
  addNetworkAdapter(networkAdapter: NetworkAdapter): void;
10
14
  send(message: MessageContents): void;
11
15
  isReady: () => boolean;
@@ -19,5 +23,7 @@ export interface NetworkSubsystemEvents {
19
23
  }
20
24
  export interface PeerPayload {
21
25
  peerId: PeerId;
26
+ storageId?: StorageId;
27
+ isEphemeral: boolean;
22
28
  }
23
29
  //# sourceMappingURL=NetworkSubsystem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAa,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AAOtB,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAUzB,MAAM;gBAAzC,QAAQ,EAAE,cAAc,EAAE,EAAS,MAAM,SAAiB;IAMtE,iBAAiB,CAAC,cAAc,EAAE,cAAc;IAsEhD,IAAI,CAAC,OAAO,EAAE,eAAe;IAsC7B,OAAO,gBAEN;IAED,SAAS,sBAUR;CACF;AAQD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACvC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;CACf"}
1
+ {"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAa,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAO/C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;IACb,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,WAAW;gBAHnB,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,QAAiB,EACtB,SAAS,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,yCAAyC;IACpF,WAAW,EAAE,OAAO;IAO9B,iBAAiB,CAAC,cAAc,EAAE,cAAc;IA2EhD,IAAI,CAAC,OAAO,EAAE,eAAe;IAsC7B,OAAO,gBAEN;IAED,SAAS,sBAUR;CACF;AAQD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACvC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;CACrB"}
@@ -4,6 +4,8 @@ import { isEphemeralMessage, isValidRepoMessage, } from "./messages.js";
4
4
  const getEphemeralMessageSource = (message) => `${message.senderId}:${message.sessionId}`;
5
5
  export class NetworkSubsystem extends EventEmitter {
6
6
  peerId;
7
+ storageId;
8
+ isEphemeral;
7
9
  #log;
8
10
  #adaptersByPeer = {};
9
11
  #count = 0;
@@ -11,9 +13,12 @@ export class NetworkSubsystem extends EventEmitter {
11
13
  #ephemeralSessionCounts = {};
12
14
  #readyAdapterCount = 0;
13
15
  #adapters = [];
14
- constructor(adapters, peerId = randomPeerId()) {
16
+ constructor(adapters, peerId = randomPeerId(), storageId, // todo: we shouldn't pass a promise here
17
+ isEphemeral) {
15
18
  super();
16
19
  this.peerId = peerId;
20
+ this.storageId = storageId;
21
+ this.isEphemeral = isEphemeral;
17
22
  this.#log = debug(`automerge-repo:network:${this.peerId}`);
18
23
  adapters.forEach(a => this.addNetworkAdapter(a));
19
24
  }
@@ -26,14 +31,14 @@ export class NetworkSubsystem extends EventEmitter {
26
31
  this.emit("ready");
27
32
  }
28
33
  });
29
- networkAdapter.on("peer-candidate", ({ peerId }) => {
34
+ networkAdapter.on("peer-candidate", ({ peerId, storageId, isEphemeral }) => {
30
35
  this.#log(`peer candidate: ${peerId} `);
31
36
  // TODO: This is where authentication would happen
32
37
  if (!this.#adaptersByPeer[peerId]) {
33
38
  // TODO: handle losing a server here
34
39
  this.#adaptersByPeer[peerId] = networkAdapter;
35
40
  }
36
- this.emit("peer", { peerId });
41
+ this.emit("peer", { peerId, storageId, isEphemeral });
37
42
  });
38
43
  networkAdapter.on("peer-disconnected", ({ peerId }) => {
39
44
  this.#log(`peer disconnected: ${peerId} `);
@@ -65,7 +70,9 @@ export class NetworkSubsystem extends EventEmitter {
65
70
  }
66
71
  });
67
72
  });
68
- networkAdapter.connect(this.peerId);
73
+ this.storageId.then(storageId => {
74
+ networkAdapter.connect(this.peerId, storageId, this.isEphemeral);
75
+ });
69
76
  }
70
77
  send(message) {
71
78
  const peer = this.#adaptersByPeer[message.targetId];
@@ -1,5 +1,6 @@
1
1
  import { SyncState } from "@automerge/automerge";
2
2
  import { DocumentId, PeerId, SessionId } from "../types.js";
3
+ import { StorageId } from "../storage/types.js";
3
4
  /**
4
5
  * A sync message for a particular document
5
6
  */
@@ -76,8 +77,28 @@ export type AuthMessage<TPayload = any> = {
76
77
  /** The payload of the auth message (up to the specific auth provider) */
77
78
  payload: TPayload;
78
79
  };
80
+ export type RemoteSubscriptionControlMessage = {
81
+ type: "remote-subscription-change";
82
+ senderId: PeerId;
83
+ targetId: PeerId;
84
+ add?: StorageId[];
85
+ remove?: StorageId[];
86
+ };
87
+ export type RemoteHeadsChanged = {
88
+ type: "remote-heads-changed";
89
+ senderId: PeerId;
90
+ targetId: PeerId;
91
+ documentId: DocumentId;
92
+ newHeads: {
93
+ [key: StorageId]: {
94
+ heads: string[];
95
+ timestamp: number;
96
+ };
97
+ };
98
+ };
79
99
  /** These are message types that a {@link NetworkAdapter} surfaces to a {@link Repo}. */
80
- export type RepoMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
100
+ export type RepoMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage | RemoteSubscriptionControlMessage | RemoteHeadsChanged;
101
+ export type DocMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
81
102
  /** These are all the message types that a {@link NetworkAdapter} might see. */
82
103
  export type Message = RepoMessage | AuthMessage;
83
104
  /**
@@ -95,4 +116,6 @@ export declare const isDocumentUnavailableMessage: (msg: Message) => msg is Docu
95
116
  export declare const isRequestMessage: (msg: Message) => msg is RequestMessage;
96
117
  export declare const isSyncMessage: (msg: Message) => msg is SyncMessage;
97
118
  export declare const isEphemeralMessage: (msg: Message) => msg is EphemeralMessage;
119
+ export declare const isRemoteSubscriptionControlMessage: (msg: Message) => msg is RemoteSubscriptionControlMessage;
120
+ export declare const isRemoteHeadsChanged: (msg: Message) => msg is RemoteHeadsChanged;
98
121
  //# sourceMappingURL=messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE3D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IAEZ,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,iCAAiC;IACjC,IAAI,EAAE,UAAU,CAAA;IAEhB,0DAA0D;IAC1D,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;;;;;KASK;AACL,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,WAAW,CAAA;IAEjB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAA;IAEb,8GAA8G;IAC9G,SAAS,EAAE,SAAS,CAAA;IAEpB,+CAA+C;IAC/C,UAAU,EAAE,UAAU,CAAA;IAEtB,qCAAqC;IACrC,IAAI,EAAE,UAAU,CAAA;CACjB,CAAA;AAED,uHAAuH;AACvH,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,iBAAiB,CAAA;IAEvB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,yDAAyD;IACzD,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;KAKK;AACL,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IAEf,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,yCAAyC;IACzC,IAAI,EAAE,UAAU,CAAA;IAEhB,4CAA4C;IAC5C,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,WAAW,CAAC,QAAQ,GAAG,GAAG,IAAI;IACxC,IAAI,EAAE,MAAM,CAAA;IAEZ,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,yEAAyE;IACzE,OAAO,EAAE,QAAQ,CAAA;CAClB,CAAA;AAED,wFAAwF;AACxF,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,0BAA0B,CAAA;AAE9B,+EAA+E;AAC/E,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,WAAW,CAAA;AAE/C;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IACrD,CAAC,SAAS,gBAAgB,GACtB,IAAI,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,CAAC,GAC3C,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;AAEzB,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB;AAID,eAAO,MAAM,kBAAkB,YAAa,OAAO,2BAOT,CAAA;AAG1C,eAAO,MAAM,4BAA4B,QAAS,OAAO,sCACzB,CAAA;AAEhC,eAAO,MAAM,gBAAgB,QAAS,OAAO,0BACrB,CAAA;AAExB,eAAO,MAAM,aAAa,QAAS,OAAO,uBACrB,CAAA;AAErB,eAAO,MAAM,kBAAkB,QAAS,OAAO,4BACrB,CAAA"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,13 @@ export const isValidRepoMessage = (message) => typeof message === "object" &&
5
5
  (isSyncMessage(message) ||
6
6
  isEphemeralMessage(message) ||
7
7
  isRequestMessage(message) ||
8
- isDocumentUnavailableMessage(message));
8
+ isDocumentUnavailableMessage(message) ||
9
+ isRemoteSubscriptionControlMessage(message) ||
10
+ isRemoteHeadsChanged(message));
9
11
  // prettier-ignore
10
12
  export const isDocumentUnavailableMessage = (msg) => msg.type === "doc-unavailable";
11
13
  export const isRequestMessage = (msg) => msg.type === "request";
12
14
  export const isSyncMessage = (msg) => msg.type === "sync";
13
15
  export const isEphemeralMessage = (msg) => msg.type === "ephemeral";
16
+ export const isRemoteSubscriptionControlMessage = (msg) => msg.type === "remote-subscription-change";
17
+ export const isRemoteHeadsChanged = (msg) => msg.type === "remote-heads-changed";
@@ -1,6 +1,7 @@
1
1
  import * as A from "@automerge/automerge/next";
2
- import { PeerId, type DocumentId } from "../types.js";
2
+ import { type DocumentId } from "../types.js";
3
3
  import { StorageAdapter } from "./StorageAdapter.js";
4
+ import { StorageId } from "./types.js";
4
5
  /**
5
6
  * The storage subsystem is responsible for saving and loading Automerge documents to and from
6
7
  * storage adapter. It also provides a generic key/value storage interface for other uses.
@@ -8,6 +9,7 @@ import { StorageAdapter } from "./StorageAdapter.js";
8
9
  export declare class StorageSubsystem {
9
10
  #private;
10
11
  constructor(storageAdapter: StorageAdapter);
12
+ id(): Promise<StorageId>;
11
13
  /** Loads a value from storage. */
12
14
  load(
13
15
  /** Namespace to prevent collisions with other users of the storage subsystem. */
@@ -44,7 +46,7 @@ export declare class StorageSubsystem {
44
46
  * Removes the Automerge document with the given ID from storage
45
47
  */
46
48
  removeDoc(documentId: DocumentId): Promise<void>;
47
- loadSyncState(documentId: DocumentId, peerId: PeerId): Promise<A.SyncState | undefined>;
48
- saveSyncState(documentId: DocumentId, peerId: PeerId, syncState: A.SyncState): Promise<void>;
49
+ loadSyncState(documentId: DocumentId, storageId: StorageId): Promise<A.SyncState | undefined>;
50
+ saveSyncState(documentId: DocumentId, storageId: StorageId, syncState: A.SyncState): Promise<void>;
49
51
  }
50
52
  //# sourceMappingURL=StorageSubsystem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAKpD;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,cAAc;IAc1C,kCAAkC;IAC5B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKlC,gCAAgC;IAC1B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM;IAEX,sCAAsC;IACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC;IAKhB,oCAAoC;IAC9B,MAAM;IACV,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,2FAA2F;IAC3F,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmClE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAkEhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAM7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;CAyCjB"}
1
+ {"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAK7D;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,cAAc;IAIpC,EAAE,IAAI,OAAO,CAAC,SAAS,CAAC;IA2B9B,kCAAkC;IAC5B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKlC,gCAAgC;IAC1B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM;IAEX,sCAAsC;IACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC;IAKhB,oCAAoC;IAC9B,MAAM;IACV,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,2FAA2F;IAC3F,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmClE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAkEhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAM7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;CAyCjB"}
@@ -4,6 +4,7 @@ import { headsAreSame } from "../helpers/headsAreSame.js";
4
4
  import { mergeArrays } from "../helpers/mergeArrays.js";
5
5
  import { keyHash, headsHash } from "./keyHash.js";
6
6
  import { chunkTypeFromKey } from "./chunkTypeFromKey.js";
7
+ import * as Uuid from "uuid";
7
8
  /**
8
9
  * The storage subsystem is responsible for saving and loading Automerge documents to and from
9
10
  * storage adapter. It also provides a generic key/value storage interface for other uses.
@@ -21,6 +22,18 @@ export class StorageSubsystem {
21
22
  constructor(storageAdapter) {
22
23
  this.#storageAdapter = storageAdapter;
23
24
  }
25
+ async id() {
26
+ let storedId = await this.#storageAdapter.load(["storage-adapter-id"]);
27
+ let id;
28
+ if (storedId) {
29
+ id = new TextDecoder().decode(storedId);
30
+ }
31
+ else {
32
+ id = Uuid.v4();
33
+ await this.#storageAdapter.save(["storage-adapter-id"], new TextEncoder().encode(id));
34
+ }
35
+ return id;
36
+ }
24
37
  // ARBITRARY KEY/VALUE STORAGE
25
38
  // The `load`, `save`, and `remove` methods are for generic key/value storage, as opposed to
26
39
  // Automerge documents. For example, they're used by the LocalFirstAuthProvider to persist the
@@ -163,13 +176,13 @@ export class StorageSubsystem {
163
176
  this.#chunkInfos.set(documentId, newChunkInfos);
164
177
  this.#compacting = false;
165
178
  }
166
- async loadSyncState(documentId, peerId) {
167
- const key = [documentId, "sync-state", peerId];
179
+ async loadSyncState(documentId, storageId) {
180
+ const key = [documentId, "sync-state", storageId];
168
181
  const loaded = await this.#storageAdapter.load(key);
169
182
  return loaded ? A.decodeSyncState(loaded) : undefined;
170
183
  }
171
- async saveSyncState(documentId, peerId, syncState) {
172
- const key = [documentId, "sync-state", peerId];
184
+ async saveSyncState(documentId, storageId, syncState) {
185
+ const key = [documentId, "sync-state", storageId];
173
186
  await this.#storageAdapter.save(key, A.encodeSyncState(syncState));
174
187
  }
175
188
  /**
@@ -34,4 +34,8 @@ export type ChunkType = "snapshot" | "incremental";
34
34
  * should not assume any particular structure.
35
35
  **/
36
36
  export type StorageKey = string[];
37
+ /** A branded type for storage IDs */
38
+ export type StorageId = string & {
39
+ __storageId: true;
40
+ };
37
41
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAElD;;;;;;;;;;;;;;;;;IAiBI;AACJ,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAElD;;;;;;;;;;;;;;;;;IAiBI;AACJ,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,CAAA;AAEjC,qCAAqC;AACrC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { Repo } from "../Repo.js";
2
- import { RepoMessage } from "../network/messages.js";
2
+ import { DocMessage } from "../network/messages.js";
3
3
  import { DocumentId, PeerId } from "../types.js";
4
4
  import { Synchronizer } from "./Synchronizer.js";
5
5
  /** A CollectionSynchronizer is responsible for synchronizing a DocCollection with peers. */
@@ -11,7 +11,7 @@ export declare class CollectionSynchronizer extends Synchronizer {
11
11
  * When we receive a sync message for a document we haven't got in memory, we
12
12
  * register it with the repo and start synchronizing
13
13
  */
14
- receiveMessage(message: RepoMessage): Promise<void>;
14
+ receiveMessage(message: DocMessage): Promise<void>;
15
15
  /**
16
16
  * Starts synchronizing the given document with all peers that we share it generously with.
17
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IA8C9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,WAAW;IAyBzC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAYlC,cAAc,CAAC,UAAU,EAAE,UAAU;IAIrC,2DAA2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM;IAgBtB,uDAAuD;IACvD,UAAU,CAAC,MAAM,EAAE,MAAM;IASzB,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;CACF"}
1
+ {"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,UAAU,EAAe,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAmD9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAyBxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAYlC,cAAc,CAAC,UAAU,EAAE,UAAU;IAIrC,2DAA2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM;IAgBtB,uDAAuD;IACvD,UAAU,CAAC,MAAM,EAAE,MAAM;IASzB,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;CACF"}
@@ -28,11 +28,15 @@ export class CollectionSynchronizer extends Synchronizer {
28
28
  #initDocSynchronizer(handle) {
29
29
  const docSynchronizer = new DocSynchronizer({
30
30
  handle,
31
- onLoadSyncState: peerId => {
31
+ onLoadSyncState: async (peerId) => {
32
32
  if (!this.repo.storageSubsystem) {
33
- return Promise.resolve(undefined);
33
+ return;
34
34
  }
35
- return this.repo.storageSubsystem.loadSyncState(handle.documentId, peerId);
35
+ const persistanceInfo = this.repo.persistanceInfoByPeerId[peerId];
36
+ if (!persistanceInfo || persistanceInfo.isEphemeral) {
37
+ return;
38
+ }
39
+ return this.repo.storageSubsystem.loadSyncState(handle.documentId, persistanceInfo.storageId);
36
40
  },
37
41
  });
38
42
  docSynchronizer.on("message", event => this.emit("message", event));
@@ -1 +1 @@
1
- {"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAG9C,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;AAIhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,SAAS,CAAA;CAC9D;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAsBV,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyB9D,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IAqID,OAAO,CAAC,MAAM,EAAE,MAAM;IAItB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA+C3B,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;CA8EzD"}
1
+ {"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAG9C,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;AAIhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,SAAS,CAAA;CAC9D;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAsBV,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyB9D,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IAyHD,OAAO,CAAC,MAAM,EAAE,MAAM;IAItB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA+C3B,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;CA8EzD"}
@@ -5,7 +5,6 @@ import { READY, REQUESTING, UNAVAILABLE, } from "../DocHandle.js";
5
5
  import { isRequestMessage, } from "../network/messages.js";
6
6
  import { Synchronizer } from "./Synchronizer.js";
7
7
  import { throttle } from "../helpers/throttle.js";
8
- import { headsAreSame } from "../helpers/headsAreSame.js";
9
8
  /**
10
9
  * DocSynchronizer takes a handle to an Automerge document, and receives & dispatches sync messages
11
10
  * to bring it inline with all other peers' versions.
@@ -98,15 +97,7 @@ export class DocSynchronizer extends Synchronizer {
98
97
  this.#syncStates[peerId] = syncState;
99
98
  }
100
99
  #setSyncState(peerId, syncState) {
101
- const previousSyncState = this.#syncStates[peerId];
102
100
  this.#syncStates[peerId] = syncState;
103
- const haveTheirSyncedHeadsChanged = syncState.theirHeads &&
104
- (!previousSyncState ||
105
- !previousSyncState.theirHeads ||
106
- !headsAreSame(previousSyncState.theirHeads, syncState.theirHeads));
107
- if (haveTheirSyncedHeadsChanged) {
108
- this.#handle.setRemoteHeads(peerId, syncState.theirHeads);
109
- }
110
101
  this.emit("sync-state", {
111
102
  peerId,
112
103
  syncState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "1.0.18",
3
+ "version": "1.1.0-alpha.1",
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>",
@@ -23,7 +23,7 @@
23
23
  "http-server": "^14.1.0"
24
24
  },
25
25
  "dependencies": {
26
- "@automerge/automerge": "^2.1.7",
26
+ "@automerge/automerge": "^2.1.8-alpha.1",
27
27
  "bs58check": "^3.0.1",
28
28
  "cbor-x": "^1.3.0",
29
29
  "debug": "^4.3.4",
@@ -55,5 +55,5 @@
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  },
58
- "gitHead": "737bde99e0387bef70b53cb0b14d8f08f48f7a92"
58
+ "gitHead": "11805d698f860bd6ffb3ca028d3b57e718690b5a"
59
59
  }
package/src/DocHandle.ts CHANGED
@@ -19,6 +19,7 @@ import { encode } from "./helpers/cbor.js"
19
19
  import { headsAreSame } from "./helpers/headsAreSame.js"
20
20
  import { withTimeout } from "./helpers/withTimeout.js"
21
21
  import type { AutomergeUrl, DocumentId, PeerId } from "./types.js"
22
+ import { StorageId } from "./storage/types.js"
22
23
 
23
24
  /** DocHandle is a wrapper around a single Automerge document that lets us
24
25
  * listen for changes and notify the network and storage of new changes.
@@ -39,7 +40,7 @@ export class DocHandle<T> //
39
40
 
40
41
  #machine: DocHandleXstateMachine<T>
41
42
  #timeoutDelay: number
42
- #remoteHeads: Record<PeerId, A.Heads> = {}
43
+ #remoteHeads: Record<StorageId, A.Heads> = {}
43
44
 
44
45
  /** The URL of this document
45
46
  *
@@ -71,9 +72,9 @@ export class DocHandle<T> //
71
72
  * Internally we use a state machine to orchestrate document loading and/or syncing, in order to
72
73
  * avoid requesting data we already have, or surfacing intermediate values to the consumer.
73
74
  *
74
- * ┌─────────────────────┬─────────TIMEOUT────►┌────────┐
75
- * ┌───┴─────┐ ┌───┴────────┐ │ failed
76
- * ┌───────┐ ┌──FIND──┤ loading ├─REQUEST──►│ requesting ├─UPDATE──┐ └────────┘
75
+ * ┌─────────────────────┬─────────TIMEOUT────►┌─────────────┐
76
+ * ┌───┴─────┐ ┌───┴────────┐ │ unavailable
77
+ * ┌───────┐ ┌──FIND──┤ loading ├─REQUEST──►│ requesting ├─UPDATE──┐ └─────────────┘
77
78
  * │ idle ├──┤ └───┬─────┘ └────────────┘ │
78
79
  * └───────┘ │ │ └─►┌────────┐
79
80
  * │ └───────LOAD───────────────────────────────►│ ready │
@@ -111,7 +112,7 @@ export class DocHandle<T> //
111
112
  after: [
112
113
  {
113
114
  delay: this.#timeoutDelay,
114
- target: FAILED,
115
+ target: UNAVAILABLE,
115
116
  },
116
117
  ],
117
118
  },
@@ -135,7 +136,7 @@ export class DocHandle<T> //
135
136
  after: [
136
137
  {
137
138
  delay: this.#timeoutDelay,
138
- target: FAILED,
139
+ target: UNAVAILABLE,
139
140
  },
140
141
  ],
141
142
  },
@@ -146,9 +147,6 @@ export class DocHandle<T> //
146
147
  DELETE: { actions: "onDelete", target: DELETED },
147
148
  },
148
149
  },
149
- failed: {
150
- type: "final",
151
- },
152
150
  deleted: {
153
151
  type: "final",
154
152
  },
@@ -240,7 +238,7 @@ export class DocHandle<T> //
240
238
  return Promise.any(
241
239
  awaitStates.map(state =>
242
240
  waitFor(this.#machine, s => s.matches(state), {
243
- timeout: this.#timeoutDelay * 2000, // longer than the delay above for testing
241
+ timeout: this.#timeoutDelay * 2, // use a longer delay here so as not to race with other delays
244
242
  })
245
243
  )
246
244
  )
@@ -294,7 +292,7 @@ export class DocHandle<T> //
294
292
  // wait for the document to enter one of the desired states
295
293
  await this.#statePromise(awaitStates)
296
294
  } catch (error) {
297
- // if we timed out (or the load has already failed), return undefined
295
+ // if we timed out (or have determined the document is currently unavailable), return undefined
298
296
  return undefined
299
297
  }
300
298
  // Return the document
@@ -328,17 +326,17 @@ export class DocHandle<T> //
328
326
  })
329
327
  }
330
328
 
331
- /** `setRemoteHeads` is called by the doc synchronizer
329
+ /** `setRemoteHeads` is called by the repo either when a doc handle changes or we receive new remote heads
332
330
  * @hidden
333
331
  */
334
- setRemoteHeads(peerId: PeerId, heads: A.Heads) {
335
- this.#remoteHeads[peerId] = heads
336
- this.emit("remote-heads", { peerId, heads })
332
+ setRemoteHeads(storageId: StorageId, heads: A.Heads) {
333
+ this.#remoteHeads[storageId] = heads
334
+ this.emit("remote-heads", { storageId, heads })
337
335
  }
338
336
 
339
- /** Returns the heads of the peer */
340
- getRemoteHeads(peerId: PeerId): A.Heads | undefined {
341
- return this.#remoteHeads[peerId]
337
+ /** Returns the heads of the storageId */
338
+ getRemoteHeads(storageId: StorageId): A.Heads | undefined {
339
+ return this.#remoteHeads[storageId]
342
340
  }
343
341
 
344
342
  /** `change` is called by the repo when the document is changed locally */
@@ -497,7 +495,7 @@ export interface DocHandleOutboundEphemeralMessagePayload<T> {
497
495
  }
498
496
 
499
497
  export interface DocHandleRemoteHeadsPayload {
500
- peerId: PeerId
498
+ storageId: StorageId
501
499
  heads: A.Heads
502
500
  }
503
501
 
@@ -538,8 +536,6 @@ export const HandleState = {
538
536
  REQUESTING: "requesting",
539
537
  /** The document is available */
540
538
  READY: "ready",
541
- /** We were unable to load or request the document for some reason */
542
- FAILED: "failed",
543
539
  /** The document has been deleted from the repo */
544
540
  DELETED: "deleted",
545
541
  /** The document was not available in storage or from any connected peers */
@@ -626,7 +622,6 @@ export const {
626
622
  AWAITING_NETWORK,
627
623
  REQUESTING,
628
624
  READY,
629
- FAILED,
630
625
  DELETED,
631
626
  UNAVAILABLE,
632
627
  } = HandleState