@automerge/automerge-repo 1.1.0-alpha.1 → 1.1.0-alpha.13

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 (58) hide show
  1. package/README.md +12 -7
  2. package/dist/AutomergeUrl.js +2 -2
  3. package/dist/RemoteHeadsSubscriptions.d.ts +1 -0
  4. package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -1
  5. package/dist/RemoteHeadsSubscriptions.js +76 -16
  6. package/dist/Repo.d.ts +23 -10
  7. package/dist/Repo.d.ts.map +1 -1
  8. package/dist/Repo.js +103 -54
  9. package/dist/helpers/debounce.js +1 -1
  10. package/dist/helpers/pause.d.ts.map +1 -1
  11. package/dist/helpers/pause.js +2 -0
  12. package/dist/helpers/throttle.js +1 -1
  13. package/dist/helpers/withTimeout.d.ts.map +1 -1
  14. package/dist/helpers/withTimeout.js +2 -0
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/network/NetworkAdapter.d.ts +14 -7
  19. package/dist/network/NetworkAdapter.d.ts.map +1 -1
  20. package/dist/network/NetworkAdapter.js +3 -3
  21. package/dist/network/NetworkSubsystem.d.ts +4 -8
  22. package/dist/network/NetworkSubsystem.d.ts.map +1 -1
  23. package/dist/network/NetworkSubsystem.js +12 -13
  24. package/dist/network/messages.d.ts +48 -38
  25. package/dist/network/messages.d.ts.map +1 -1
  26. package/dist/network/messages.js +7 -9
  27. package/dist/storage/StorageSubsystem.d.ts.map +1 -1
  28. package/dist/storage/StorageSubsystem.js +7 -2
  29. package/dist/storage/keyHash.d.ts.map +1 -1
  30. package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
  31. package/dist/synchronizer/CollectionSynchronizer.js +5 -3
  32. package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
  33. package/dist/synchronizer/DocSynchronizer.js +20 -8
  34. package/dist/synchronizer/Synchronizer.d.ts +12 -3
  35. package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
  36. package/package.json +6 -6
  37. package/src/AutomergeUrl.ts +2 -2
  38. package/src/RemoteHeadsSubscriptions.ts +85 -16
  39. package/src/Repo.ts +131 -68
  40. package/src/helpers/debounce.ts +1 -1
  41. package/src/helpers/pause.ts +4 -0
  42. package/src/helpers/throttle.ts +1 -1
  43. package/src/helpers/withTimeout.ts +2 -0
  44. package/src/index.ts +2 -1
  45. package/src/network/NetworkAdapter.ts +18 -12
  46. package/src/network/NetworkSubsystem.ts +23 -24
  47. package/src/network/messages.ts +77 -68
  48. package/src/storage/StorageSubsystem.ts +7 -2
  49. package/src/storage/keyHash.ts +2 -0
  50. package/src/synchronizer/CollectionSynchronizer.ts +7 -4
  51. package/src/synchronizer/DocSynchronizer.ts +27 -15
  52. package/src/synchronizer/Synchronizer.ts +13 -3
  53. package/test/RemoteHeadsSubscriptions.test.ts +34 -24
  54. package/test/Repo.test.ts +57 -2
  55. package/test/StorageSubsystem.test.ts +1 -1
  56. package/test/helpers/waitForMessages.ts +22 -0
  57. package/test/remoteHeads.test.ts +197 -72
  58. package/.eslintrc +0 -28
package/dist/index.d.ts CHANGED
@@ -29,13 +29,13 @@ export { DocHandle } from "./DocHandle.js";
29
29
  export { isValidAutomergeUrl, parseAutomergeUrl, stringifyAutomergeUrl, } from "./AutomergeUrl.js";
30
30
  export { Repo } from "./Repo.js";
31
31
  export { NetworkAdapter } from "./network/NetworkAdapter.js";
32
- export { isValidRepoMessage } from "./network/messages.js";
32
+ export { isRepoMessage } from "./network/messages.js";
33
33
  export { StorageAdapter } from "./storage/StorageAdapter.js";
34
34
  /** @hidden **/
35
35
  export * as cbor from "./helpers/cbor.js";
36
36
  export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedChangePayload, DocHandleEphemeralMessagePayload, DocHandleRemoteHeadsPayload, DocHandleEvents, DocHandleOptions, DocHandleOutboundEphemeralMessagePayload, HandleState, } from "./DocHandle.js";
37
37
  export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
38
- export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, } from "./network/NetworkAdapter.js";
38
+ export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, PeerMetadata, } from "./network/NetworkAdapter.js";
39
39
  export type { DocumentUnavailableMessage, EphemeralMessage, Message, RepoMessage, RequestMessage, SyncMessage, } from "./network/messages.js";
40
40
  export type { Chunk, ChunkInfo, ChunkType, StorageKey, StorageId, } from "./storage/types.js";
41
41
  export * from "./types.js";
@@ -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,EACV,SAAS,GACV,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,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,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,EACvB,YAAY,GACb,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"}
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ export { DocHandle } from "./DocHandle.js";
29
29
  export { isValidAutomergeUrl, parseAutomergeUrl, stringifyAutomergeUrl, } from "./AutomergeUrl.js";
30
30
  export { Repo } from "./Repo.js";
31
31
  export { NetworkAdapter } from "./network/NetworkAdapter.js";
32
- export { isValidRepoMessage } from "./network/messages.js";
32
+ export { isRepoMessage } from "./network/messages.js";
33
33
  export { StorageAdapter } from "./storage/StorageAdapter.js";
34
34
  /** @hidden **/
35
35
  export * as cbor from "./helpers/cbor.js";
@@ -2,6 +2,16 @@ import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
3
  import { Message } from "./messages.js";
4
4
  import { StorageId } from "../storage/types.js";
5
+ /**
6
+ * Describes a peer intent to the system
7
+ * storageId: the key for syncState to decide what the other peer already has
8
+ * isEphemeral: to decide if we bother recording this peer's sync state
9
+ *
10
+ */
11
+ export interface PeerMetadata {
12
+ storageId?: StorageId;
13
+ isEphemeral?: boolean;
14
+ }
5
15
  /** An interface representing some way to connect to other peers
6
16
  *
7
17
  * @remarks
@@ -11,15 +21,13 @@ import { StorageId } from "../storage/types.js";
11
21
  */
12
22
  export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
13
23
  peerId?: PeerId;
14
- storageId?: StorageId;
15
- isEphemeral: boolean;
24
+ peerMetadata?: PeerMetadata;
16
25
  /** Called by the {@link Repo} to start the connection process
17
26
  *
18
27
  * @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
28
+ * @argument peerMetadata - how this adapter should present itself to other peers
21
29
  */
22
- abstract connect(peerId: PeerId, storageId: StorageId | undefined, isEphemeral: boolean): void;
30
+ abstract connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
23
31
  /** Called by the {@link Repo} to send a message to a peer
24
32
  *
25
33
  * @argument message - the message to send
@@ -45,8 +53,7 @@ export interface OpenPayload {
45
53
  }
46
54
  export interface PeerCandidatePayload {
47
55
  peerId: PeerId;
48
- storageId?: StorageId;
49
- isEphemeral: boolean;
56
+ peerMetadata: PeerMetadata;
50
57
  }
51
58
  export interface PeerDisconnectedPayload {
52
59
  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;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"}
1
+ {"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAEA,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;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI;IAEnE;;;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,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
@@ -1,3 +1,4 @@
1
+ /* c8 ignore start */
1
2
  import { EventEmitter } from "eventemitter3";
2
3
  /** An interface representing some way to connect to other peers
3
4
  *
@@ -7,7 +8,6 @@ import { EventEmitter } from "eventemitter3";
7
8
  * until the adapter emits a `ready` event before it starts trying to use it
8
9
  */
9
10
  export class NetworkAdapter extends EventEmitter {
10
- peerId; // hmmm, maybe not
11
- storageId;
12
- isEphemeral = true;
11
+ peerId;
12
+ peerMetadata;
13
13
  }
@@ -1,15 +1,12 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
- import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js";
3
+ import type { NetworkAdapter, PeerDisconnectedPayload, PeerMetadata } from "./NetworkAdapter.js";
4
4
  import { MessageContents, RepoMessage } from "./messages.js";
5
- import { StorageId } from "../storage/types.js";
6
5
  export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
7
6
  #private;
8
7
  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);
8
+ private peerMetadata;
9
+ constructor(adapters: NetworkAdapter[], peerId: PeerId, peerMetadata: Promise<PeerMetadata>);
13
10
  addNetworkAdapter(networkAdapter: NetworkAdapter): void;
14
11
  send(message: MessageContents): void;
15
12
  isReady: () => boolean;
@@ -23,7 +20,6 @@ export interface NetworkSubsystemEvents {
23
20
  }
24
21
  export interface PeerPayload {
25
22
  peerId: PeerId;
26
- storageId?: StorageId;
27
- isEphemeral: boolean;
23
+ peerMetadata: PeerMetadata;
28
24
  }
29
25
  //# 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;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"}
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,KAAK,EACV,cAAc,EACd,uBAAuB,EACvB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AAOtB,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;IACb,OAAO,CAAC,YAAY;gBAFpB,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,QAAiB,EACtB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC;IAO7C,iBAAiB,CAAC,cAAc,EAAE,cAAc;IAyEhD,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,YAAY,EAAE,YAAY,CAAA;CAC3B"}
@@ -1,11 +1,10 @@
1
1
  import debug from "debug";
2
2
  import { EventEmitter } from "eventemitter3";
3
- import { isEphemeralMessage, isValidRepoMessage, } from "./messages.js";
3
+ import { isEphemeralMessage, isRepoMessage, } 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
+ peerMetadata;
9
8
  #log;
10
9
  #adaptersByPeer = {};
11
10
  #count = 0;
@@ -13,12 +12,10 @@ export class NetworkSubsystem extends EventEmitter {
13
12
  #ephemeralSessionCounts = {};
14
13
  #readyAdapterCount = 0;
15
14
  #adapters = [];
16
- constructor(adapters, peerId = randomPeerId(), storageId, // todo: we shouldn't pass a promise here
17
- isEphemeral) {
15
+ constructor(adapters, peerId = randomPeerId(), peerMetadata) {
18
16
  super();
19
17
  this.peerId = peerId;
20
- this.storageId = storageId;
21
- this.isEphemeral = isEphemeral;
18
+ this.peerMetadata = peerMetadata;
22
19
  this.#log = debug(`automerge-repo:network:${this.peerId}`);
23
20
  adapters.forEach(a => this.addNetworkAdapter(a));
24
21
  }
@@ -31,14 +28,14 @@ export class NetworkSubsystem extends EventEmitter {
31
28
  this.emit("ready");
32
29
  }
33
30
  });
34
- networkAdapter.on("peer-candidate", ({ peerId, storageId, isEphemeral }) => {
31
+ networkAdapter.on("peer-candidate", ({ peerId, peerMetadata }) => {
35
32
  this.#log(`peer candidate: ${peerId} `);
36
33
  // TODO: This is where authentication would happen
37
34
  if (!this.#adaptersByPeer[peerId]) {
38
35
  // TODO: handle losing a server here
39
36
  this.#adaptersByPeer[peerId] = networkAdapter;
40
37
  }
41
- this.emit("peer", { peerId, storageId, isEphemeral });
38
+ this.emit("peer", { peerId, peerMetadata });
42
39
  });
43
40
  networkAdapter.on("peer-disconnected", ({ peerId }) => {
44
41
  this.#log(`peer disconnected: ${peerId} `);
@@ -46,7 +43,7 @@ export class NetworkSubsystem extends EventEmitter {
46
43
  this.emit("peer-disconnected", { peerId });
47
44
  });
48
45
  networkAdapter.on("message", msg => {
49
- if (!isValidRepoMessage(msg)) {
46
+ if (!isRepoMessage(msg)) {
50
47
  this.#log(`invalid message: ${JSON.stringify(msg)}`);
51
48
  return;
52
49
  }
@@ -70,8 +67,10 @@ export class NetworkSubsystem extends EventEmitter {
70
67
  }
71
68
  });
72
69
  });
73
- this.storageId.then(storageId => {
74
- networkAdapter.connect(this.peerId, storageId, this.isEphemeral);
70
+ this.peerMetadata.then(peerMetadata => {
71
+ networkAdapter.connect(this.peerId, peerMetadata);
72
+ }).catch(err => {
73
+ this.#log("error connecting to network", err);
75
74
  });
76
75
  }
77
76
  send(message) {
@@ -108,7 +107,7 @@ export class NetworkSubsystem extends EventEmitter {
108
107
  }
109
108
  };
110
109
  const outbound = prepareMessage(message);
111
- this.#log("sending message", outbound);
110
+ this.#log("sending message %o", outbound);
112
111
  peer.send(outbound);
113
112
  }
114
113
  isReady = () => {
@@ -1,56 +1,64 @@
1
1
  import { SyncState } from "@automerge/automerge";
2
- import { DocumentId, PeerId, SessionId } from "../types.js";
3
2
  import { StorageId } from "../storage/types.js";
3
+ import { DocumentId, PeerId, SessionId } from "../types.js";
4
+ export type Message = {
5
+ type: string;
6
+ /** The peer ID of the sender of this message */
7
+ senderId: PeerId;
8
+ /** The peer ID of the recipient of this message */
9
+ targetId: PeerId;
10
+ data?: Uint8Array;
11
+ documentId?: DocumentId;
12
+ };
4
13
  /**
5
14
  * A sync message for a particular document
6
15
  */
7
16
  export type SyncMessage = {
8
17
  type: "sync";
9
- /** The peer ID of the sender of this message */
10
18
  senderId: PeerId;
11
- /** The peer ID of the recipient of this message */
12
19
  targetId: PeerId;
13
20
  /** The automerge sync message */
14
21
  data: Uint8Array;
15
22
  /** The document ID of the document this message is for */
16
23
  documentId: DocumentId;
17
24
  };
18
- /** An ephemeral message
25
+ /**
26
+ * An ephemeral message.
19
27
  *
20
28
  * @remarks
21
- * Ephemeral messages are not persisted anywhere and have no particular
22
- * structure. `automerge-repo` will gossip them around, in order to avoid
23
- * eternal loops of ephemeral messages every message has a session ID, which
24
- * is a random number generated by the sender at startup time, and a sequence
25
- * number. The combination of these two things allows us to discard messages
26
- * we have already seen.
29
+ * Ephemeral messages are not persisted anywhere. The data property can be used by the application
30
+ * as needed. The repo gossips these around.
31
+ *
32
+ * In order to avoid infinite loops of ephemeral messages, every message has (a) a session ID, which
33
+ * is a random number generated by the sender at startup time; and (b) a sequence number. The
34
+ * combination of these two things allows us to discard messages we have already seen.
27
35
  * */
28
36
  export type EphemeralMessage = {
29
37
  type: "ephemeral";
30
- /** The peer ID of the sender of this message */
31
38
  senderId: PeerId;
32
- /** The peer ID of the recipient of this message */
33
39
  targetId: PeerId;
34
- /** A sequence number which must be incremented for each message sent by this peer */
40
+ /** A sequence number which must be incremented for each message sent by this peer. */
35
41
  count: number;
36
- /** The ID of the session this message is part of. The sequence number for a given session always increases */
42
+ /** The ID of the session this message is part of. The sequence number for a given session always increases. */
37
43
  sessionId: SessionId;
38
- /** The document ID this message pertains to */
44
+ /** The document ID this message pertains to. */
39
45
  documentId: DocumentId;
40
- /** The actual data of the message */
46
+ /** The actual data of the message. */
41
47
  data: Uint8Array;
42
48
  };
43
- /** Sent by a {@link Repo} to indicate that it does not have the document and none of it's connected peers do either */
49
+ /**
50
+ * Sent by a {@link Repo} to indicate that it does not have the document and none of its connected
51
+ * peers do either.
52
+ */
44
53
  export type DocumentUnavailableMessage = {
45
54
  type: "doc-unavailable";
46
- /** The peer ID of the sender of this message */
47
55
  senderId: PeerId;
48
- /** The peer ID of the recipient of this message */
49
56
  targetId: PeerId;
50
57
  /** The document which the peer claims it doesn't have */
51
58
  documentId: DocumentId;
52
59
  };
53
- /** Sent by a {@link Repo} to request a document from a peer
60
+ /**
61
+ * Sent by a {@link Repo} to request a document from a peer.
54
62
  *
55
63
  * @remarks
56
64
  * This is identical to a {@link SyncMessage} except that it is sent by a {@link Repo}
@@ -58,37 +66,35 @@ export type DocumentUnavailableMessage = {
58
66
  * */
59
67
  export type RequestMessage = {
60
68
  type: "request";
61
- /** The peer ID of the sender of this message */
62
69
  senderId: PeerId;
63
- /** The peer ID of the recipient of this message */
64
70
  targetId: PeerId;
65
- /** The initial automerge sync message */
71
+ /** The automerge sync message */
66
72
  data: Uint8Array;
67
- /** The document ID this message requests */
73
+ /** The document ID of the document this message is for */
68
74
  documentId: DocumentId;
69
75
  };
70
- /** (anticipating work in progress) */
71
- export type AuthMessage<TPayload = any> = {
72
- type: "auth";
73
- /** The peer ID of the sender of this message */
74
- senderId: PeerId;
75
- /** The peer ID of the recipient of this message */
76
- targetId: PeerId;
77
- /** The payload of the auth message (up to the specific auth provider) */
78
- payload: TPayload;
79
- };
76
+ /**
77
+ * Sent by a {@link Repo} to add or remove storage IDs from a remote peer's subscription.
78
+ */
80
79
  export type RemoteSubscriptionControlMessage = {
81
80
  type: "remote-subscription-change";
82
81
  senderId: PeerId;
83
82
  targetId: PeerId;
83
+ /** The storage IDs to add to the subscription */
84
84
  add?: StorageId[];
85
+ /** The storage IDs to remove from the subscription */
85
86
  remove?: StorageId[];
86
87
  };
88
+ /**
89
+ * Sent by a {@link Repo} to indicate that the heads of a document have changed on a remote peer.
90
+ */
87
91
  export type RemoteHeadsChanged = {
88
92
  type: "remote-heads-changed";
89
93
  senderId: PeerId;
90
94
  targetId: PeerId;
95
+ /** The document ID of the document that has changed */
91
96
  documentId: DocumentId;
97
+ /** The document's new heads */
92
98
  newHeads: {
93
99
  [key: StorageId]: {
94
100
  heads: string[];
@@ -98,20 +104,24 @@ export type RemoteHeadsChanged = {
98
104
  };
99
105
  /** These are message types that a {@link NetworkAdapter} surfaces to a {@link Repo}. */
100
106
  export type RepoMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage | RemoteSubscriptionControlMessage | RemoteHeadsChanged;
107
+ /** These are message types that are handled by the {@link CollectionSynchronizer}.*/
101
108
  export type DocMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
102
- /** These are all the message types that a {@link NetworkAdapter} might see. */
103
- export type Message = RepoMessage | AuthMessage;
104
109
  /**
105
110
  * The contents of a message, without the sender ID or other properties added by the {@link NetworkSubsystem})
106
111
  */
107
- export type MessageContents<T extends Message = Message> = T extends EphemeralMessage ? Omit<T, "senderId" | "count" | "sessionId"> : Omit<T, "senderId">;
112
+ export type MessageContents<T extends Message = RepoMessage> = T extends EphemeralMessage ? Omit<T, "senderId" | "count" | "sessionId"> : Omit<T, "senderId">;
108
113
  /** Notify the repo that the sync state has changed */
109
114
  export interface SyncStateMessage {
110
115
  peerId: PeerId;
111
116
  documentId: DocumentId;
112
117
  syncState: SyncState;
113
118
  }
114
- export declare const isValidRepoMessage: (message: Message) => message is RepoMessage;
119
+ /** Notify the repo that a peer started syncing with a doc */
120
+ export interface OpenDocMessage {
121
+ peerId: PeerId;
122
+ documentId: DocumentId;
123
+ }
124
+ export declare const isRepoMessage: (message: Message) => message is RepoMessage;
115
125
  export declare const isDocumentUnavailableMessage: (msg: Message) => msg is DocumentUnavailableMessage;
116
126
  export declare const isRequestMessage: (msg: Message) => msg is RequestMessage;
117
127
  export declare const isSyncMessage: (msg: Message) => msg is SyncMessage;
@@ -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;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;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,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,4BAA4B,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;CACtB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE;QAAC,CAAC,GAAG,EAAE,SAAS,GAAG;YAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC,CAAC;CACpE,CAAA;AAED,wFAAwF;AACxF,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,0BAA0B,GAC1B,gCAAgC,GAChC,kBAAkB,CAAA;AAEtB,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,cAAc,GAAG,0BAA0B,CAAA;AAErG,+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,2BASjB,CAAA;AAGlC,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;AAE1B,eAAO,MAAM,kCAAkC,QAAS,OAAO,4CACpB,CAAA;AAE3C,eAAO,MAAM,oBAAoB,QAAS,OAAO,8BACZ,CAAA"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,15 @@
1
1
  // TYPE GUARDS
2
- export const isValidRepoMessage = (message) => typeof message === "object" &&
3
- typeof message.type === "string" &&
4
- typeof message.senderId === "string" &&
5
- (isSyncMessage(message) ||
6
- isEphemeralMessage(message) ||
7
- isRequestMessage(message) ||
8
- isDocumentUnavailableMessage(message) ||
9
- isRemoteSubscriptionControlMessage(message) ||
10
- isRemoteHeadsChanged(message));
2
+ export const isRepoMessage = (message) => isSyncMessage(message) ||
3
+ isEphemeralMessage(message) ||
4
+ isRequestMessage(message) ||
5
+ isDocumentUnavailableMessage(message) ||
6
+ isRemoteSubscriptionControlMessage(message) ||
7
+ isRemoteHeadsChanged(message);
11
8
  // prettier-ignore
12
9
  export const isDocumentUnavailableMessage = (msg) => msg.type === "doc-unavailable";
13
10
  export const isRequestMessage = (msg) => msg.type === "request";
14
11
  export const isSyncMessage = (msg) => msg.type === "sync";
15
12
  export const isEphemeralMessage = (msg) => msg.type === "ephemeral";
13
+ // prettier-ignore
16
14
  export const isRemoteSubscriptionControlMessage = (msg) => msg.type === "remote-subscription-change";
17
15
  export const isRemoteHeadsChanged = (msg) => msg.type === "remote-heads-changed";
@@ -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,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"}
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;CA8CjB"}
@@ -23,7 +23,7 @@ export class StorageSubsystem {
23
23
  this.#storageAdapter = storageAdapter;
24
24
  }
25
25
  async id() {
26
- let storedId = await this.#storageAdapter.load(["storage-adapter-id"]);
26
+ const storedId = await this.#storageAdapter.load(["storage-adapter-id"]);
27
27
  let id;
28
28
  if (storedId) {
29
29
  id = new TextDecoder().decode(storedId);
@@ -217,6 +217,11 @@ export class StorageSubsystem {
217
217
  incrementalSize += chunk.size;
218
218
  }
219
219
  }
220
- return incrementalSize >= snapshotSize;
220
+ // if the file is currently small, don't worry, just compact
221
+ // this might seem a bit arbitrary (1k is arbitrary) but is designed to ensure compaction
222
+ // for documents with only a single large change on top of an empty (or nearly empty) document
223
+ // for example: imported NPM modules, images, etc.
224
+ // if we have even more incrementals (so far) than the snapshot, compact
225
+ return snapshotSize < 1024 || incrementalSize >= snapshotSize;
221
226
  }
222
227
  }
@@ -1 +1 @@
1
- {"version":3,"file":"keyHash.d.ts","sourceRoot":"","sources":["../../src/storage/keyHash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,UAIzC;AACD,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,MAAM,CAIhD"}
1
+ {"version":3,"file":"keyHash.d.ts","sourceRoot":"","sources":["../../src/storage/keyHash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,UAIzC;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,MAAM,CAIhD"}
@@ -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,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"}
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;AACnD,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;IAqD9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAyBxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAalC,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"}
@@ -32,14 +32,15 @@ export class CollectionSynchronizer extends Synchronizer {
32
32
  if (!this.repo.storageSubsystem) {
33
33
  return;
34
34
  }
35
- const persistanceInfo = this.repo.persistanceInfoByPeerId[peerId];
36
- if (!persistanceInfo || persistanceInfo.isEphemeral) {
35
+ const { storageId, isEphemeral } = this.repo.peerMetadataByPeerId[peerId] || {};
36
+ if (!storageId || isEphemeral) {
37
37
  return;
38
38
  }
39
- return this.repo.storageSubsystem.loadSyncState(handle.documentId, persistanceInfo.storageId);
39
+ return this.repo.storageSubsystem.loadSyncState(handle.documentId, storageId);
40
40
  },
41
41
  });
42
42
  docSynchronizer.on("message", event => this.emit("message", event));
43
+ docSynchronizer.on("open-doc", event => this.emit("open-doc", event));
43
44
  docSynchronizer.on("sync-state", event => this.emit("sync-state", event));
44
45
  return docSynchronizer;
45
46
  }
@@ -86,6 +87,7 @@ export class CollectionSynchronizer extends Synchronizer {
86
87
  });
87
88
  }
88
89
  // TODO: implement this
90
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
89
91
  removeDocument(documentId) {
90
92
  throw new Error("not implemented");
91
93
  }
@@ -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;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"}
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;AAGhD,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;IAkID,OAAO,CAAC,MAAM,EAAE,MAAM;IAItB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IAmD3B,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"}
@@ -66,9 +66,7 @@ export class DocSynchronizer extends Synchronizer {
66
66
  this.emit("message", message);
67
67
  }
68
68
  #withSyncState(peerId, callback) {
69
- if (!this.#peers.includes(peerId)) {
70
- this.#peers.push(peerId);
71
- }
69
+ this.#addPeer(peerId);
72
70
  if (!(peerId in this.#peerDocumentStatuses)) {
73
71
  this.#peerDocumentStatuses[peerId] = "unknown";
74
72
  }
@@ -79,13 +77,23 @@ export class DocSynchronizer extends Synchronizer {
79
77
  }
80
78
  let pendingCallbacks = this.#pendingSyncStateCallbacks[peerId];
81
79
  if (!pendingCallbacks) {
82
- this.#onLoadSyncState(peerId).then(syncState => {
80
+ this.#onLoadSyncState(peerId)
81
+ .then(syncState => {
83
82
  this.#initSyncState(peerId, syncState ?? A.initSyncState());
83
+ })
84
+ .catch(err => {
85
+ this.#log(`Error loading sync state for ${peerId}: ${err}`);
84
86
  });
85
87
  pendingCallbacks = this.#pendingSyncStateCallbacks[peerId] = [];
86
88
  }
87
89
  pendingCallbacks.push(callback);
88
90
  }
91
+ #addPeer(peerId) {
92
+ if (!this.#peers.includes(peerId)) {
93
+ this.#peers.push(peerId);
94
+ this.emit("open-doc", { documentId: this.documentId, peerId });
95
+ }
96
+ }
89
97
  #initSyncState(peerId, syncState) {
90
98
  const pendingCallbacks = this.#pendingSyncStateCallbacks[peerId];
91
99
  if (pendingCallbacks) {
@@ -170,10 +178,14 @@ export class DocSynchronizer extends Synchronizer {
170
178
  // TODO: cover that case with a test and remove this hack
171
179
  const reparsedSyncState = A.decodeSyncState(A.encodeSyncState(syncState));
172
180
  this.#setSyncState(peerId, reparsedSyncState);
173
- docPromise.then(doc => {
181
+ docPromise
182
+ .then(doc => {
174
183
  if (doc) {
175
184
  this.#sendSyncMessage(peerId, doc);
176
185
  }
186
+ })
187
+ .catch(err => {
188
+ this.#log(`Error loading doc for ${peerId}: ${err}`);
177
189
  });
178
190
  });
179
191
  });
@@ -227,9 +239,9 @@ export class DocSynchronizer extends Synchronizer {
227
239
  return;
228
240
  }
229
241
  this.#processAllPendingSyncMessages();
230
- this.#processSyncMessage(message, new Date());
242
+ this.#processSyncMessage(message);
231
243
  }
232
- #processSyncMessage(message, received) {
244
+ #processSyncMessage(message) {
233
245
  if (isRequestMessage(message)) {
234
246
  this.#peerDocumentStatuses[message.senderId] = "wants";
235
247
  }
@@ -270,7 +282,7 @@ export class DocSynchronizer extends Synchronizer {
270
282
  }
271
283
  #processAllPendingSyncMessages() {
272
284
  for (const message of this.#pendingSyncMessages) {
273
- this.#processSyncMessage(message.message, message.received);
285
+ this.#processSyncMessage(message.message);
274
286
  }
275
287
  this.#pendingSyncMessages = [];
276
288
  }
@@ -1,10 +1,19 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
- import { MessageContents, RepoMessage, SyncStateMessage } from "../network/messages.js";
2
+ import { MessageContents, OpenDocMessage, RepoMessage } from "../network/messages.js";
3
+ import { SyncState } from "@automerge/automerge";
4
+ import { PeerId, DocumentId } from "../types.js";
3
5
  export declare abstract class Synchronizer extends EventEmitter<SynchronizerEvents> {
4
6
  abstract receiveMessage(message: RepoMessage): void;
5
7
  }
6
8
  export interface SynchronizerEvents {
7
- message: (arg: MessageContents) => void;
8
- "sync-state": (arg: SyncStateMessage) => void;
9
+ message: (payload: MessageContents) => void;
10
+ "sync-state": (payload: SyncStatePayload) => void;
11
+ "open-doc": (arg: OpenDocMessage) => void;
12
+ }
13
+ /** Notify the repo that the sync state has changed */
14
+ export interface SyncStatePayload {
15
+ peerId: PeerId;
16
+ documentId: DocumentId;
17
+ syncState: SyncState;
9
18
  }
10
19
  //# sourceMappingURL=Synchronizer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/Synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EACjB,MAAM,wBAAwB,CAAA;AAE/B,8BAAsB,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;IACvC,YAAY,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAC9C"}
1
+ {"version":3,"file":"Synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/Synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhD,8BAAsB,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACjD,UAAU,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;CAC1C;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB"}