@automerge/automerge-repo 1.1.0 → 1.1.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 (44) hide show
  1. package/README.md +2 -2
  2. package/dist/DocHandle.d.ts.map +1 -1
  3. package/dist/DocHandle.js +4 -5
  4. package/dist/Repo.d.ts +4 -4
  5. package/dist/Repo.d.ts.map +1 -1
  6. package/dist/Repo.js +2 -4
  7. package/dist/helpers/tests/network-adapter-tests.d.ts +2 -2
  8. package/dist/helpers/tests/network-adapter-tests.d.ts.map +1 -1
  9. package/dist/helpers/tests/network-adapter-tests.js +16 -1
  10. package/dist/index.d.ts +3 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/network/NetworkAdapter.d.ts +4 -34
  13. package/dist/network/NetworkAdapter.d.ts.map +1 -1
  14. package/dist/network/NetworkAdapter.js +1 -0
  15. package/dist/network/NetworkAdapterInterface.d.ts +61 -0
  16. package/dist/network/NetworkAdapterInterface.d.ts.map +1 -0
  17. package/dist/network/NetworkAdapterInterface.js +2 -0
  18. package/dist/network/NetworkSubsystem.d.ts +3 -3
  19. package/dist/network/NetworkSubsystem.d.ts.map +1 -1
  20. package/dist/network/NetworkSubsystem.js +4 -2
  21. package/dist/storage/StorageAdapter.d.ts +3 -1
  22. package/dist/storage/StorageAdapter.d.ts.map +1 -1
  23. package/dist/storage/StorageAdapter.js +1 -0
  24. package/dist/storage/StorageAdapterInterface.d.ts +30 -0
  25. package/dist/storage/StorageAdapterInterface.d.ts.map +1 -0
  26. package/dist/storage/StorageAdapterInterface.js +1 -0
  27. package/dist/storage/StorageSubsystem.d.ts +2 -2
  28. package/dist/storage/StorageSubsystem.d.ts.map +1 -1
  29. package/dist/synchronizer/DocSynchronizer.js +2 -2
  30. package/package.json +2 -2
  31. package/src/DocHandle.ts +7 -8
  32. package/src/Repo.ts +11 -15
  33. package/src/helpers/tests/network-adapter-tests.ts +30 -4
  34. package/src/index.ts +3 -1
  35. package/src/network/NetworkAdapter.ts +7 -45
  36. package/src/network/NetworkAdapterInterface.ts +77 -0
  37. package/src/network/NetworkSubsystem.ts +13 -11
  38. package/src/storage/StorageAdapter.ts +3 -1
  39. package/src/storage/StorageAdapterInterface.ts +34 -0
  40. package/src/storage/StorageSubsystem.ts +3 -3
  41. package/src/synchronizer/DocSynchronizer.ts +3 -3
  42. package/test/DocHandle.test.ts +24 -1
  43. package/test/Repo.test.ts +32 -1
  44. package/test/helpers/DummyNetworkAdapter.ts +37 -5
package/README.md CHANGED
@@ -38,8 +38,8 @@ This library provides two main components: the `Repo` itself, and the `DocHandle
38
38
 
39
39
  A `Repo` exposes these methods:
40
40
 
41
- - `create<T>()`
42
- Creates a new, empty `Automerge.Doc` and returns a `DocHandle` for it.
41
+ - `create<T>(initialValue: T?)`
42
+ Creates a new `Automerge.Doc` and returns a `DocHandle` for it. Accepts an optional initial value for the document. Produces an empty document (potentially violating the type!) otherwise.
43
43
  - `find<T>(docId: DocumentId)`
44
44
  Looks up a given document either on the local machine or (if necessary) over any configured
45
45
  networks.
@@ -1 +1 @@
1
- {"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EASL,UAAU,EAEX,MAAM,QAAQ,CAAA;AAMf,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C;;;;;;;;;;;KAWK;AACL,qBAAa,SAAS,CAAC,CAAC,CAAE,EAAE;AAC1B,SAAQ,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;;IAmB/B,UAAU,EAAE,UAAU;IAX/B;;;;OAIG;IACH,IAAI,GAAG,IAAI,YAAY,CAEtB;IAED,cAAc;gBAEL,UAAU,EAAE,UAAU,EAC7B,OAAO,GAAE,gBAAgB,CAAC,CAAC,CAAM;IA0MnC;;;;OAIG;IACH,OAAO,gBAA0C;IACjD;;;;;OAKG;IACH,SAAS,gBAA4C;IACrD,aAAa,gBAAgD;IAC7D,OAAO,WAAY,WAAW,EAAE,aACmB;IAEnD,cAAc;IACd,IAAI,KAAK,eAER;IAED;;;;;OAKG;IACG,SAAS,CAAC,WAAW,GAAE,WAAW,EAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE;;;;;;OAMG;IACG,GAAG,CACP,WAAW,GAAE,WAAW,EAAyB,GAChD,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAYhC;;;;;;;;;OASG;IACH,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS;IAQ/B;;SAEK;IACL,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAM5C;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK;IAKnD,yCAAyC;IACzC,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,GAAG,SAAS;IAIzD,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAM;IAehE;;;OAGG;IACH,QAAQ,CACN,KAAK,EAAE,CAAC,CAAC,KAAK,EACd,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EACvB,OAAO,GAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAM,GAC/B,MAAM,EAAE,GAAG,SAAS;IAmBvB;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;IAc/B,WAAW;IAIX;;SAEK;IACL,OAAO;IAIP,cAAc;IACd,YAAY;IAIZ,cAAc;IACd,YAAY;IAIZ,kEAAkE;IAClE,MAAM;IAIN;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,OAAO;CAM3B;AAID,cAAc;AACd,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAE1B;IACE,gGAAgG;IAChG,KAAK,EAAE,IAAI,CAAA;IAEX,yCAAyC;IACzC,YAAY,CAAC,EAAE,CAAC,CAAA;CACjB,GAED;IACE,KAAK,CAAC,EAAE,KAAK,CAAA;IAEb,+HAA+H;IAC/H,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAEL,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,6BAA6B,CAAC,CAAC;IAC9C,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;CACd;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;CACrB;AAED,0CAA0C;AAC1C,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,iDAAiD;IACjD,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACb,wDAAwD;IACxD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAA;IAClB,mCAAmC;IACnC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;CAC1B;AAED,MAAM,WAAW,gCAAgC,CAAC,CAAC;IACjD,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,wCAAwC,CAAC,CAAC;IACzD,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAA;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,CAAC,CAAC,SAAS,CAAA;CACvB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACpE,MAAM,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACpD,MAAM,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACpD,WAAW,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACzD,mBAAmB,EAAE,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAC3E,4BAA4B,EAAE,CAC5B,OAAO,EAAE,wCAAwC,CAAC,CAAC,CAAC,KACjD,IAAI,CAAA;IACT,cAAc,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAA;CAC/D;AAMD;;;;GAIG;AACH,eAAO,MAAM,WAAW;IACtB,kEAAkE;;IAElE,mDAAmD;;IAEnD,sDAAsD;;IAEtD,6EAA6E;;IAE7E,gCAAgC;;IAEhC,kDAAkD;;IAElD,4EAA4E;;CAEpE,CAAA;AACV,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAkBxE,eAAO,MAAM,KAAK;;;;;;;;;;;CAWR,CAAA;AA8CV,eAAO,MACL,IAAI,UACJ,OAAO,aACP,gBAAgB,qBAChB,UAAU,gBACV,KAAK,WACL,OAAO,aACP,WAAW,eACE,CAAA"}
1
+ {"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EASL,UAAU,EAEX,MAAM,QAAQ,CAAA;AAMf,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C;;;;;;;;;;;KAWK;AACL,qBAAa,SAAS,CAAC,CAAC,CAAE,EAAE;AAC1B,SAAQ,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;;IAmB/B,UAAU,EAAE,UAAU;IAX/B;;;;OAIG;IACH,IAAI,GAAG,IAAI,YAAY,CAEtB;IAED,cAAc;gBAEL,UAAU,EAAE,UAAU,EAC7B,OAAO,GAAE,gBAAgB,CAAC,CAAC,CAAM;IAyMnC;;;;OAIG;IACH,OAAO,gBAA0C;IACjD;;;;;OAKG;IACH,SAAS,gBAA4C;IACrD,aAAa,gBAAgD;IAC7D,OAAO,WAAY,WAAW,EAAE,aACmB;IAEnD,cAAc;IACd,IAAI,KAAK,eAER;IAED;;;;;OAKG;IACG,SAAS,CAAC,WAAW,GAAE,WAAW,EAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE;;;;;;OAMG;IACG,GAAG,CACP,WAAW,GAAE,WAAW,EAAyB,GAChD,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAYhC;;;;;;;;;OASG;IACH,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS;IAQ/B;;SAEK;IACL,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAM5C;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK;IAKnD,yCAAyC;IACzC,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,GAAG,SAAS;IAIzD,2EAA2E;IAC3E,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAM;IAehE;;;OAGG;IACH,QAAQ,CACN,KAAK,EAAE,CAAC,CAAC,KAAK,EACd,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EACvB,OAAO,GAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAM,GAC/B,MAAM,EAAE,GAAG,SAAS;IAmBvB;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;IAc/B,WAAW;IAIX;;SAEK;IACL,OAAO;IAIP,cAAc;IACd,YAAY;IAIZ,cAAc;IACd,YAAY;IAIZ,kEAAkE;IAClE,MAAM;IAIN;;;;;OAKG;IACH,SAAS,CAAC,OAAO,EAAE,OAAO;CAM3B;AAID,cAAc;AACd,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAE1B;IACE,gGAAgG;IAChG,KAAK,EAAE,IAAI,CAAA;IAEX,yCAAyC;IACzC,YAAY,CAAC,EAAE,CAAC,CAAA;CACjB,GAED;IACE,KAAK,CAAC,EAAE,KAAK,CAAA;IAEb,+HAA+H;IAC/H,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAEL,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,6BAA6B,CAAC,CAAC;IAC9C,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;CACd;AAED,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;CACrB;AAED,0CAA0C;AAC1C,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,iDAAiD;IACjD,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACb,wDAAwD;IACxD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAA;IAClB,mCAAmC;IACnC,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;CAC1B;AAED,MAAM,WAAW,gCAAgC,CAAC,CAAC;IACjD,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,wCAAwC,CAAC,CAAC;IACzD,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACpB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAA;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,CAAC,CAAC,SAAS,CAAA;CACvB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACpE,MAAM,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACpD,MAAM,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACpD,WAAW,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IACzD,mBAAmB,EAAE,CAAC,OAAO,EAAE,gCAAgC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAC3E,4BAA4B,EAAE,CAC5B,OAAO,EAAE,wCAAwC,CAAC,CAAC,CAAC,KACjD,IAAI,CAAA;IACT,cAAc,EAAE,CAAC,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAA;CAC/D;AAMD;;;;GAIG;AACH,eAAO,MAAM,WAAW;IACtB,kEAAkE;;IAElE,mDAAmD;;IAEnD,sDAAsD;;IAEtD,6EAA6E;;IAE7E,gCAAgC;;IAEhC,kDAAkD;;IAElD,4EAA4E;;CAEpE,CAAA;AACV,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAkBxE,eAAO,MAAM,KAAK;;;;;;;;;;;CAWR,CAAA;AA8CV,eAAO,MACL,IAAI,UACJ,OAAO,aACP,gBAAgB,qBAChB,UAAU,gBACV,KAAK,WACL,OAAO,aACP,WAAW,eACE,CAAA"}
package/dist/DocHandle.js CHANGED
@@ -201,11 +201,10 @@ export class DocHandle//
201
201
  }
202
202
  /** Returns a promise that resolves when the docHandle is in one of the given states */
203
203
  #statePromise(awaitStates) {
204
- if (!Array.isArray(awaitStates))
205
- awaitStates = [awaitStates];
206
- return Promise.any(awaitStates.map(state => waitFor(this.#machine, s => s.matches(state), {
207
- timeout: this.#timeoutDelay * 2, // use a longer delay here so as not to race with other delays
208
- })));
204
+ const awaitStatesArray = Array.isArray(awaitStates) ? awaitStates : [awaitStates];
205
+ return waitFor(this.#machine, s => awaitStatesArray.some((state) => s.matches(state)),
206
+ // use a longer delay here so as not to race with other delays
207
+ { timeout: this.#timeoutDelay * 2 });
209
208
  }
210
209
  // PUBLIC
211
210
  /**
package/dist/Repo.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import { DocHandle } from "./DocHandle.js";
3
- import { NetworkAdapter, type PeerMetadata } from "./network/NetworkAdapter.js";
3
+ import { NetworkAdapterInterface, type PeerMetadata } from "./network/NetworkAdapterInterface.js";
4
4
  import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
5
- import { StorageAdapter } from "./storage/StorageAdapter.js";
5
+ import { StorageAdapterInterface } from "./storage/StorageAdapterInterface.js";
6
6
  import { StorageSubsystem } from "./storage/StorageSubsystem.js";
7
7
  import { StorageId } from "./storage/types.js";
8
8
  import type { AnyDocumentId, DocumentId, PeerId } from "./types.js";
@@ -90,9 +90,9 @@ export interface RepoConfig {
90
90
  * Sync state is only persisted for non-ephemeral peers */
91
91
  isEphemeral?: boolean;
92
92
  /** A storage adapter can be provided, or not */
93
- storage?: StorageAdapter;
93
+ storage?: StorageAdapterInterface;
94
94
  /** One or more network adapters must be provided */
95
- network: NetworkAdapter[];
95
+ network: NetworkAdapterInterface[];
96
96
  /**
97
97
  * Normal peers typically share generously with everyone (meaning we sync all our documents with
98
98
  * all peers). A server only syncs documents that a peer explicitly requests by ID.
@@ -1 +1 @@
1
- {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAM5C,OAAO,EAAE,SAAS,EAAiC,MAAM,gBAAgB,CAAA;AAIzE,OAAO,EAAE,uBAAuB,EAAE,KAAK,YAAY,EAAE,MAAM,sCAAsC,CAAA;AACjG,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;AAG9C,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnE,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;IAMtB,sDAAsD;IACtD,cAAc;IACd,WAAW,EAAE,WAAW,CAAmB;IAE3C,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAK3C,EACV,OAAO,EACP,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAmC,EACnC,0BAAkC,GACnC,EAAE,UAAU;IAqRb,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;IAYzC;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAuBnC;;;OAGG;IACH,IAAI,CAAC,CAAC;IACJ,sDAAsD;IACtD,EAAE,EAAE,aAAa,GAChB,SAAS,CAAC,CAAC,CAAC;IAwBf,MAAM;IACJ,oDAAoD;IACpD,EAAE,EAAE,aAAa;IAWnB;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAShE;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU;IAY5B,kBAAkB,YAAa,SAAS,EAAE,UASzC;IAED,SAAS,QAAa,QAAQ,SAAS,GAAG,SAAS,CAAC,CAMnD;CACF;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,oDAAoD;IACpD,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAElC;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IAEzB;;OAEG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAA;CACrC;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;CAC7D;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAA;CACvB"}
package/dist/Repo.js CHANGED
@@ -114,12 +114,10 @@ export class Repo extends EventEmitter {
114
114
  this.storageSubsystem = storageSubsystem;
115
115
  // NETWORK
116
116
  // The network subsystem deals with sending and receiving messages to and from peers.
117
- const myPeerMetadata = new Promise(
118
- // eslint-disable-next-line no-async-promise-executor -- TODO: fix
119
- async (resolve) => resolve({
117
+ const myPeerMetadata = (async () => ({
120
118
  storageId: await storageSubsystem?.id(),
121
119
  isEphemeral,
122
- }));
120
+ }))();
123
121
  const networkSubsystem = new NetworkSubsystem(network, peerId, myPeerMetadata);
124
122
  this.networkSubsystem = networkSubsystem;
125
123
  // When we get a new peer, register it with the synchronizer
@@ -1,4 +1,4 @@
1
- import { type NetworkAdapter } from "../../index.js";
1
+ import type { NetworkAdapterInterface } from "../../network/NetworkAdapterInterface.js";
2
2
  /**
3
3
  * Runs a series of tests against a set of three peers, each represented by one or more instantiated
4
4
  * network adapters.
@@ -12,7 +12,7 @@ import { type NetworkAdapter } from "../../index.js";
12
12
  * to clean up any resources that were created during the test.
13
13
  */
14
14
  export declare function runAdapterTests(_setup: SetupFn, title?: string): void;
15
- type Network = NetworkAdapter | NetworkAdapter[];
15
+ type Network = NetworkAdapterInterface | NetworkAdapterInterface[];
16
16
  export type SetupFn = () => Promise<{
17
17
  adapters: [Network, Network, Network];
18
18
  teardown?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"network-adapter-tests.d.ts","sourceRoot":"","sources":["../../../src/helpers/tests/network-adapter-tests.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAIlE;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CA8HrE;AAID,KAAK,OAAO,GAAG,cAAc,GAAG,cAAc,EAAE,CAAA;AAEhD,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC;IAClC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAC,CAAA"}
1
+ {"version":3,"file":"network-adapter-tests.d.ts","sourceRoot":"","sources":["../../../src/helpers/tests/network-adapter-tests.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAA;AAIvF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAuJrE;AAID,KAAK,OAAO,GAAG,uBAAuB,GAAG,uBAAuB,EAAE,CAAA;AAElE,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC;IAClC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAC,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import assert from "assert";
2
- import { describe, it } from "vitest";
2
+ import { describe, expect, it } from "vitest";
3
3
  import { Repo } from "../../index.js";
4
4
  import { eventPromise, eventPromises } from "../eventPromise.js";
5
5
  import { pause } from "../pause.js";
@@ -110,6 +110,21 @@ export function runAdapterTests(_setup, title) {
110
110
  assert.deepStrictEqual(message, alicePresenceData);
111
111
  teardown();
112
112
  });
113
+ it("emits a peer-candidate event with proper peer metadata when a peer connects", async () => {
114
+ const { adapters, teardown } = await setup();
115
+ const a = adapters[0][0];
116
+ const b = adapters[1][0];
117
+ const bPromise = eventPromise(b, "peer-candidate");
118
+ const aPeerMetadata = { storageId: "a" };
119
+ b.connect("b", { storageId: "b" });
120
+ a.connect("a", aPeerMetadata);
121
+ const peerCandidate = await bPromise;
122
+ expect(peerCandidate).toMatchObject({
123
+ peerId: "a",
124
+ peerMetadata: aPeerMetadata,
125
+ });
126
+ teardown();
127
+ });
113
128
  });
114
129
  }
115
130
  const NO_OP = () => { };
package/dist/index.d.ts CHANGED
@@ -29,13 +29,15 @@ 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 type { NetworkAdapterInterface } from "./network/NetworkAdapterInterface.js";
32
33
  export { isRepoMessage } from "./network/messages.js";
33
34
  export { StorageAdapter } from "./storage/StorageAdapter.js";
35
+ export type { StorageAdapterInterface } from "./storage/StorageAdapterInterface.js";
34
36
  /** @hidden **/
35
37
  export * as cbor from "./helpers/cbor.js";
36
38
  export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedChangePayload, DocHandleEphemeralMessagePayload, DocHandleRemoteHeadsPayload, DocHandleEvents, DocHandleOptions, DocHandleOutboundEphemeralMessagePayload, HandleState, } from "./DocHandle.js";
37
39
  export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
38
- export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, PeerMetadata, } from "./network/NetworkAdapter.js";
40
+ export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, PeerMetadata, } from "./network/NetworkAdapterInterface.js";
39
41
  export type { DocumentUnavailableMessage, EphemeralMessage, Message, RepoMessage, RequestMessage, SyncMessage, } from "./network/messages.js";
40
42
  export type { Chunk, ChunkInfo, ChunkType, StorageKey, StorageId, } from "./storage/types.js";
41
43
  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,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"}
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,YAAY,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,YAAY,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAEnF,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,sCAAsC,CAAA;AAE7C,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,25 +1,17 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
+ import { NetworkAdapterEvents, PeerMetadata } from "../index.js";
2
3
  import { PeerId } from "../types.js";
3
4
  import { Message } from "./messages.js";
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
+ import { NetworkAdapterInterface } from "./NetworkAdapterInterface.js";
15
6
  /** An interface representing some way to connect to other peers
7
+ * @deprecated use {@link NetworkAdapterInterface}
16
8
  *
17
9
  * @remarks
18
10
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
19
11
  * Because the network may take some time to be ready the {@link Repo} will wait
20
12
  * until the adapter emits a `ready` event before it starts trying to use it
21
13
  */
22
- export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
14
+ export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> implements NetworkAdapterInterface {
23
15
  peerId?: PeerId;
24
16
  peerMetadata?: PeerMetadata;
25
17
  /** Called by the {@link Repo} to start the connection process
@@ -36,26 +28,4 @@ export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapter
36
28
  /** Called by the {@link Repo} to disconnect from the network */
37
29
  abstract disconnect(): void;
38
30
  }
39
- export interface NetworkAdapterEvents {
40
- /** Emitted when the network is ready to be used */
41
- ready: (payload: OpenPayload) => void;
42
- /** Emitted when the network is closed */
43
- close: () => void;
44
- /** Emitted when the network adapter learns about a new peer */
45
- "peer-candidate": (payload: PeerCandidatePayload) => void;
46
- /** Emitted when the network adapter learns that a peer has disconnected */
47
- "peer-disconnected": (payload: PeerDisconnectedPayload) => void;
48
- /** Emitted when the network adapter receives a message from a peer */
49
- message: (payload: Message) => void;
50
- }
51
- export interface OpenPayload {
52
- network: NetworkAdapter;
53
- }
54
- export interface PeerCandidatePayload {
55
- peerId: PeerId;
56
- peerMetadata: PeerMetadata;
57
- }
58
- export interface PeerDisconnectedPayload {
59
- peerId: PeerId;
60
- }
61
31
  //# sourceMappingURL=NetworkAdapter.d.ts.map
@@ -1 +1 @@
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
+ {"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,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAEtE;;;;;;;GAOG;AACH,8BAAsB,cACpB,SAAQ,YAAY,CAAC,oBAAoB,CACzC,YAAW,uBAAuB;IAElC,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"}
@@ -1,6 +1,7 @@
1
1
  /* c8 ignore start */
2
2
  import { EventEmitter } from "eventemitter3";
3
3
  /** An interface representing some way to connect to other peers
4
+ * @deprecated use {@link NetworkAdapterInterface}
4
5
  *
5
6
  * @remarks
6
7
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
@@ -0,0 +1,61 @@
1
+ import { EventEmitter } from "eventemitter3";
2
+ import { PeerId } from "../types.js";
3
+ import { Message } from "./messages.js";
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
+ }
15
+ /** An interface representing some way to connect to other peers
16
+ *
17
+ * @remarks
18
+ * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
19
+ * Because the network may take some time to be ready the {@link Repo} will wait
20
+ * until the adapter emits a `ready` event before it starts trying to use it
21
+ */
22
+ export interface NetworkAdapterInterface extends EventEmitter<NetworkAdapterEvents> {
23
+ peerId?: PeerId;
24
+ peerMetadata?: PeerMetadata;
25
+ /** Called by the {@link Repo} to start the connection process
26
+ *
27
+ * @argument peerId - the peerId of this repo
28
+ * @argument peerMetadata - how this adapter should present itself to other peers
29
+ */
30
+ connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
31
+ /** Called by the {@link Repo} to send a message to a peer
32
+ *
33
+ * @argument message - the message to send
34
+ */
35
+ send(message: Message): void;
36
+ /** Called by the {@link Repo} to disconnect from the network */
37
+ disconnect(): void;
38
+ }
39
+ export interface NetworkAdapterEvents {
40
+ /** Emitted when the network is ready to be used */
41
+ ready: (payload: OpenPayload) => void;
42
+ /** Emitted when the network is closed */
43
+ close: () => void;
44
+ /** Emitted when the network adapter learns about a new peer */
45
+ "peer-candidate": (payload: PeerCandidatePayload) => void;
46
+ /** Emitted when the network adapter learns that a peer has disconnected */
47
+ "peer-disconnected": (payload: PeerDisconnectedPayload) => void;
48
+ /** Emitted when the network adapter receives a message from a peer */
49
+ message: (payload: Message) => void;
50
+ }
51
+ export interface OpenPayload {
52
+ network: NetworkAdapterInterface;
53
+ }
54
+ export interface PeerCandidatePayload {
55
+ peerId: PeerId;
56
+ peerMetadata: PeerMetadata;
57
+ }
58
+ export interface PeerDisconnectedPayload {
59
+ peerId: PeerId;
60
+ }
61
+ //# sourceMappingURL=NetworkAdapterInterface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetworkAdapterInterface.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapterInterface.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,MAAM,WAAW,uBAAwB,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IACjF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAE1D;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAE5B,gEAAgE;IAChE,UAAU,IAAI,IAAI,CAAA;CACnB;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,uBAAuB,CAAA;CACjC;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"}
@@ -0,0 +1,2 @@
1
+ /* c8 ignore start */
2
+ export {};
@@ -1,13 +1,13 @@
1
1
  import { EventEmitter } from "eventemitter3";
2
2
  import { PeerId } from "../types.js";
3
- import type { NetworkAdapter, PeerDisconnectedPayload, PeerMetadata } from "./NetworkAdapter.js";
3
+ import type { NetworkAdapterInterface, PeerDisconnectedPayload, PeerMetadata } from "./NetworkAdapterInterface.js";
4
4
  import { MessageContents, RepoMessage } from "./messages.js";
5
5
  export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
6
6
  #private;
7
7
  peerId: PeerId;
8
8
  private peerMetadata;
9
- constructor(adapters: NetworkAdapter[], peerId: PeerId, peerMetadata: Promise<PeerMetadata>);
10
- addNetworkAdapter(networkAdapter: NetworkAdapter): void;
9
+ constructor(adapters: NetworkAdapterInterface[], peerId: PeerId, peerMetadata: Promise<PeerMetadata>);
10
+ addNetworkAdapter(networkAdapter: NetworkAdapterInterface): void;
11
11
  send(message: MessageContents): void;
12
12
  isReady: () => boolean;
13
13
  whenReady: () => Promise<void>;
@@ -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,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
+ {"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,uBAAuB,EACvB,uBAAuB,EACvB,YAAY,EACb,MAAM,8BAA8B,CAAA;AACrC,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,uBAAuB,EAAE,EAC5B,MAAM,QAAiB,EACtB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC;IAO7C,iBAAiB,CAAC,cAAc,EAAE,uBAAuB;IA2EzD,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"}
@@ -67,9 +67,11 @@ export class NetworkSubsystem extends EventEmitter {
67
67
  }
68
68
  });
69
69
  });
70
- this.peerMetadata.then(peerMetadata => {
70
+ this.peerMetadata
71
+ .then(peerMetadata => {
71
72
  networkAdapter.connect(this.peerId, peerMetadata);
72
- }).catch(err => {
73
+ })
74
+ .catch(err => {
73
75
  this.#log("error connecting to network", err);
74
76
  });
75
77
  }
@@ -1,11 +1,13 @@
1
+ import { StorageAdapterInterface } from "./StorageAdapterInterface.js";
1
2
  import { StorageKey, Chunk } from "./types.js";
2
3
  /** A storage adapter represents some way of storing binary data for a {@link Repo}
4
+ * @deprecated use {@link StorageAdapterInterface}
3
5
  *
4
6
  * @remarks
5
7
  * `StorageAdapter`s provide a key/value storage interface. The keys are arrays of strings
6
8
  * ({@link StorageKey}) and the values are binary blobs.
7
9
  */
8
- export declare abstract class StorageAdapter {
10
+ export declare abstract class StorageAdapter implements StorageAdapterInterface {
9
11
  /** Load the single value corresponding to `key` */
10
12
  abstract load(key: StorageKey): Promise<Uint8Array | undefined>;
11
13
  /** Save the value `data` to the key `key` */
@@ -1 +1 @@
1
- {"version":3,"file":"StorageAdapter.d.ts","sourceRoot":"","sources":["../../src/storage/StorageAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;GAKG;AACH,8BAAsB,cAAc;IAClC,mDAAmD;IACnD,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAE/D,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/D,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAE3D,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAC3D"}
1
+ {"version":3,"file":"StorageAdapter.d.ts","sourceRoot":"","sources":["../../src/storage/StorageAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;;GAMG;AACH,8BAAsB,cAAe,YAAW,uBAAuB;IACrE,mDAAmD;IACnD,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAE/D,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/D,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAE3D,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAC3D"}
@@ -1,4 +1,5 @@
1
1
  /** A storage adapter represents some way of storing binary data for a {@link Repo}
2
+ * @deprecated use {@link StorageAdapterInterface}
2
3
  *
3
4
  * @remarks
4
5
  * `StorageAdapter`s provide a key/value storage interface. The keys are arrays of strings
@@ -0,0 +1,30 @@
1
+ import { StorageKey, Chunk } from "./types.js";
2
+ /** A storage adapter represents some way of storing binary data for a {@link Repo}
3
+ *
4
+ * @remarks
5
+ * `StorageAdapter`s provide a key/value storage interface. The keys are arrays of strings
6
+ * ({@link StorageKey}) and the values are binary blobs.
7
+ */
8
+ export interface StorageAdapterInterface {
9
+ /** Load the single value corresponding to `key` */
10
+ load(key: StorageKey): Promise<Uint8Array | undefined>;
11
+ /** Save the value `data` to the key `key` */
12
+ save(key: StorageKey, data: Uint8Array): Promise<void>;
13
+ /** Remove the value corresponding to `key` */
14
+ remove(key: StorageKey): Promise<void>;
15
+ /**
16
+ * Load all values with keys that start with `keyPrefix`.
17
+ *
18
+ * @remarks
19
+ * The `keyprefix` will match any key that starts with the given array. For example:
20
+ * - `[documentId, "incremental"]` will match all incremental saves
21
+ * - `[documentId]` will match all data for a given document.
22
+ *
23
+ * Be careful! `[documentId]` would also match something like `[documentId, "syncState"]`! We
24
+ * aren't using this yet but keep it in mind.)
25
+ */
26
+ loadRange(keyPrefix: StorageKey): Promise<Chunk[]>;
27
+ /** Remove all values with keys that start with `keyPrefix` */
28
+ removeRange(keyPrefix: StorageKey): Promise<void>;
29
+ }
30
+ //# sourceMappingURL=StorageAdapterInterface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageAdapterInterface.d.ts","sourceRoot":"","sources":["../../src/storage/StorageAdapterInterface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,mDAAmD;IACnD,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;IAEtD,6CAA6C;IAC7C,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEtD,8CAA8C;IAC9C,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEtC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAA;IAElD,8DAA8D;IAC9D,WAAW,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClD"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
1
  import * as A from "@automerge/automerge/next";
2
2
  import { type DocumentId } from "../types.js";
3
- import { StorageAdapter } from "./StorageAdapter.js";
3
+ import { StorageAdapterInterface } from "./StorageAdapterInterface.js";
4
4
  import { StorageId } from "./types.js";
5
5
  /**
6
6
  * The storage subsystem is responsible for saving and loading Automerge documents to and from
@@ -8,7 +8,7 @@ import { StorageId } from "./types.js";
8
8
  */
9
9
  export declare class StorageSubsystem {
10
10
  #private;
11
- constructor(storageAdapter: StorageAdapter);
11
+ constructor(storageAdapter: StorageAdapterInterface);
12
12
  id(): Promise<StorageId>;
13
13
  /** Loads a value from storage. */
14
14
  load(
@@ -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;CA8CjB"}
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,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAK7D;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,uBAAuB;IAI7C,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"}
@@ -152,7 +152,7 @@ export class DocSynchronizer extends Synchronizer {
152
152
  return this.#peers.includes(peerId);
153
153
  }
154
154
  beginSync(peerIds) {
155
- const newPeers = new Set(peerIds.filter(peerId => !this.#peers.includes(peerId)));
155
+ const noPeersWithDocument = peerIds.every((peerId) => this.#peerDocumentStatuses[peerId] in ["unavailable", "wants"]);
156
156
  // At this point if we don't have anything in our storage, we need to use an empty doc to sync
157
157
  // with; but we don't want to surface that state to the front end
158
158
  const docPromise = this.#handle
@@ -162,7 +162,7 @@ export class DocSynchronizer extends Synchronizer {
162
162
  this.#syncStarted = true;
163
163
  this.#checkDocUnavailable();
164
164
  const wasUnavailable = doc === undefined;
165
- if (wasUnavailable && newPeers.size == 0) {
165
+ if (wasUnavailable && noPeersWithDocument) {
166
166
  return;
167
167
  }
168
168
  // If the doc is unavailable we still need a blank document to generate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "1.1.0",
3
+ "version": "1.1.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>",
@@ -55,5 +55,5 @@
55
55
  "publishConfig": {
56
56
  "access": "public"
57
57
  },
58
- "gitHead": "e9e7d3f27ec2ac8a2e9d122ece80598918940067"
58
+ "gitHead": "7e0681014b8c5f672e2abc2a653a954ccb6d7aba"
59
59
  }
package/src/DocHandle.ts CHANGED
@@ -39,7 +39,7 @@ export class DocHandle<T> //
39
39
  #log: debug.Debugger
40
40
 
41
41
  #machine: DocHandleXstateMachine<T>
42
- #timeoutDelay: number = 60_000
42
+ #timeoutDelay = 60_000
43
43
  #remoteHeads: Record<StorageId, A.Heads> = {}
44
44
 
45
45
  /** The URL of this document
@@ -244,13 +244,12 @@ export class DocHandle<T> //
244
244
 
245
245
  /** Returns a promise that resolves when the docHandle is in one of the given states */
246
246
  #statePromise(awaitStates: HandleState | HandleState[]) {
247
- if (!Array.isArray(awaitStates)) awaitStates = [awaitStates]
248
- return Promise.any(
249
- awaitStates.map(state =>
250
- waitFor(this.#machine, s => s.matches(state), {
251
- timeout: this.#timeoutDelay * 2, // use a longer delay here so as not to race with other delays
252
- })
253
- )
247
+ const awaitStatesArray = Array.isArray(awaitStates) ? awaitStates : [awaitStates]
248
+ return waitFor(
249
+ this.#machine,
250
+ s => awaitStatesArray.some((state) => s.matches(state)),
251
+ // use a longer delay here so as not to race with other delays
252
+ {timeout: this.#timeoutDelay * 2}
254
253
  )
255
254
  }
256
255
 
package/src/Repo.ts CHANGED
@@ -2,18 +2,18 @@ import { next as Automerge } from "@automerge/automerge"
2
2
  import debug from "debug"
3
3
  import { EventEmitter } from "eventemitter3"
4
4
  import {
5
- generateAutomergeUrl,
6
- interpretAsDocumentId,
7
- parseAutomergeUrl,
5
+ generateAutomergeUrl,
6
+ interpretAsDocumentId,
7
+ parseAutomergeUrl,
8
8
  } from "./AutomergeUrl.js"
9
9
  import { DocHandle, DocHandleEncodedChangePayload } from "./DocHandle.js"
10
10
  import { RemoteHeadsSubscriptions } from "./RemoteHeadsSubscriptions.js"
11
11
  import { headsAreSame } from "./helpers/headsAreSame.js"
12
12
  import { throttle } from "./helpers/throttle.js"
13
- import { NetworkAdapter, type PeerMetadata } from "./network/NetworkAdapter.js"
13
+ import { NetworkAdapterInterface, type PeerMetadata } from "./network/NetworkAdapterInterface.js"
14
14
  import { NetworkSubsystem } from "./network/NetworkSubsystem.js"
15
15
  import { RepoMessage } from "./network/messages.js"
16
- import { StorageAdapter } from "./storage/StorageAdapter.js"
16
+ import { StorageAdapterInterface } from "./storage/StorageAdapterInterface.js"
17
17
  import { StorageSubsystem } from "./storage/StorageSubsystem.js"
18
18
  import { StorageId } from "./storage/types.js"
19
19
  import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js"
@@ -155,14 +155,10 @@ export class Repo extends EventEmitter<RepoEvents> {
155
155
  // NETWORK
156
156
  // The network subsystem deals with sending and receiving messages to and from peers.
157
157
 
158
- const myPeerMetadata: Promise<PeerMetadata> = new Promise(
159
- // eslint-disable-next-line no-async-promise-executor -- TODO: fix
160
- async resolve =>
161
- resolve({
162
- storageId: await storageSubsystem?.id(),
163
- isEphemeral,
164
- } as PeerMetadata)
165
- )
158
+ const myPeerMetadata: Promise<PeerMetadata> = (async () => ({
159
+ storageId: await storageSubsystem?.id(),
160
+ isEphemeral,
161
+ }))()
166
162
 
167
163
  const networkSubsystem = new NetworkSubsystem(
168
164
  network,
@@ -517,10 +513,10 @@ export interface RepoConfig {
517
513
  isEphemeral?: boolean
518
514
 
519
515
  /** A storage adapter can be provided, or not */
520
- storage?: StorageAdapter
516
+ storage?: StorageAdapterInterface
521
517
 
522
518
  /** One or more network adapters must be provided */
523
- network: NetworkAdapter[]
519
+ network: NetworkAdapterInterface[]
524
520
 
525
521
  /**
526
522
  * Normal peers typically share generously with everyone (meaning we sync all our documents with
@@ -1,6 +1,7 @@
1
1
  import assert from "assert"
2
- import { describe, it } from "vitest"
3
- import { PeerId, Repo, type NetworkAdapter } from "../../index.js"
2
+ import { describe, expect, it } from "vitest"
3
+ import { PeerId, PeerMetadata, Repo, StorageId } from "../../index.js"
4
+ import type { NetworkAdapterInterface } from "../../network/NetworkAdapterInterface.js"
4
5
  import { eventPromise, eventPromises } from "../eventPromise.js"
5
6
  import { pause } from "../pause.js"
6
7
 
@@ -29,7 +30,10 @@ export function runAdapterTests(_setup: SetupFn, title?: string): void {
29
30
 
30
31
  describe(`Adapter acceptance tests ${title ? `(${title})` : ""}`, () => {
31
32
  it("can sync 2 repos", async () => {
32
- const doTest = async (a: NetworkAdapter[], b: NetworkAdapter[]) => {
33
+ const doTest = async (
34
+ a: NetworkAdapterInterface[],
35
+ b: NetworkAdapterInterface[]
36
+ ) => {
33
37
  const aliceRepo = new Repo({ network: a, peerId: alice })
34
38
  const bobRepo = new Repo({ network: b, peerId: bob })
35
39
 
@@ -141,12 +145,34 @@ export function runAdapterTests(_setup: SetupFn, title?: string): void {
141
145
  assert.deepStrictEqual(message, alicePresenceData)
142
146
  teardown()
143
147
  })
148
+
149
+ it("emits a peer-candidate event with proper peer metadata when a peer connects", async () => {
150
+ const { adapters, teardown } = await setup()
151
+ const a = adapters[0][0]
152
+ const b = adapters[1][0]
153
+
154
+ const bPromise = eventPromise(b, "peer-candidate")
155
+
156
+ const aPeerMetadata: PeerMetadata = { storageId: "a" as StorageId }
157
+
158
+ b.connect("b" as PeerId, { storageId: "b" as StorageId })
159
+ a.connect("a" as PeerId, aPeerMetadata)
160
+
161
+ const peerCandidate = await bPromise
162
+
163
+ expect(peerCandidate).toMatchObject({
164
+ peerId: "a",
165
+ peerMetadata: aPeerMetadata,
166
+ })
167
+
168
+ teardown()
169
+ })
144
170
  })
145
171
  }
146
172
 
147
173
  const NO_OP = () => {}
148
174
 
149
- type Network = NetworkAdapter | NetworkAdapter[]
175
+ type Network = NetworkAdapterInterface | NetworkAdapterInterface[]
150
176
 
151
177
  export type SetupFn = () => Promise<{
152
178
  adapters: [Network, Network, Network]
package/src/index.ts CHANGED
@@ -34,8 +34,10 @@ export {
34
34
  } from "./AutomergeUrl.js"
35
35
  export { Repo } from "./Repo.js"
36
36
  export { NetworkAdapter } from "./network/NetworkAdapter.js"
37
+ export type { NetworkAdapterInterface } from "./network/NetworkAdapterInterface.js"
37
38
  export { isRepoMessage } from "./network/messages.js"
38
39
  export { StorageAdapter } from "./storage/StorageAdapter.js"
40
+ export type { StorageAdapterInterface } from "./storage/StorageAdapterInterface.js"
39
41
 
40
42
  /** @hidden **/
41
43
  export * as cbor from "./helpers/cbor.js"
@@ -68,7 +70,7 @@ export type {
68
70
  PeerCandidatePayload,
69
71
  PeerDisconnectedPayload,
70
72
  PeerMetadata,
71
- } from "./network/NetworkAdapter.js"
73
+ } from "./network/NetworkAdapterInterface.js"
72
74
 
73
75
  export type {
74
76
  DocumentUnavailableMessage,
@@ -1,29 +1,23 @@
1
1
  /* c8 ignore start */
2
2
 
3
3
  import { EventEmitter } from "eventemitter3"
4
+ import { NetworkAdapterEvents, PeerMetadata } from "../index.js"
4
5
  import { PeerId } from "../types.js"
5
6
  import { Message } from "./messages.js"
6
- import { StorageId } from "../storage/types.js"
7
-
8
- /**
9
- * Describes a peer intent to the system
10
- * storageId: the key for syncState to decide what the other peer already has
11
- * isEphemeral: to decide if we bother recording this peer's sync state
12
- *
13
- */
14
- export interface PeerMetadata {
15
- storageId?: StorageId
16
- isEphemeral?: boolean
17
- }
7
+ import { NetworkAdapterInterface } from "./NetworkAdapterInterface.js"
18
8
 
19
9
  /** An interface representing some way to connect to other peers
10
+ * @deprecated use {@link NetworkAdapterInterface}
20
11
  *
21
12
  * @remarks
22
13
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
23
14
  * Because the network may take some time to be ready the {@link Repo} will wait
24
15
  * until the adapter emits a `ready` event before it starts trying to use it
25
16
  */
26
- export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
17
+ export abstract class NetworkAdapter
18
+ extends EventEmitter<NetworkAdapterEvents>
19
+ implements NetworkAdapterInterface
20
+ {
27
21
  peerId?: PeerId
28
22
  peerMetadata?: PeerMetadata
29
23
 
@@ -43,35 +37,3 @@ export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents>
43
37
  /** Called by the {@link Repo} to disconnect from the network */
44
38
  abstract disconnect(): void
45
39
  }
46
-
47
- // events & payloads
48
-
49
- export interface NetworkAdapterEvents {
50
- /** Emitted when the network is ready to be used */
51
- ready: (payload: OpenPayload) => void
52
-
53
- /** Emitted when the network is closed */
54
- close: () => void
55
-
56
- /** Emitted when the network adapter learns about a new peer */
57
- "peer-candidate": (payload: PeerCandidatePayload) => void
58
-
59
- /** Emitted when the network adapter learns that a peer has disconnected */
60
- "peer-disconnected": (payload: PeerDisconnectedPayload) => void
61
-
62
- /** Emitted when the network adapter receives a message from a peer */
63
- message: (payload: Message) => void
64
- }
65
-
66
- export interface OpenPayload {
67
- network: NetworkAdapter
68
- }
69
-
70
- export interface PeerCandidatePayload {
71
- peerId: PeerId
72
- peerMetadata: PeerMetadata
73
- }
74
-
75
- export interface PeerDisconnectedPayload {
76
- peerId: PeerId
77
- }
@@ -0,0 +1,77 @@
1
+ /* c8 ignore start */
2
+
3
+ import { EventEmitter } from "eventemitter3"
4
+ import { PeerId } from "../types.js"
5
+ import { Message } from "./messages.js"
6
+ import { StorageId } from "../storage/types.js"
7
+
8
+ /**
9
+ * Describes a peer intent to the system
10
+ * storageId: the key for syncState to decide what the other peer already has
11
+ * isEphemeral: to decide if we bother recording this peer's sync state
12
+ *
13
+ */
14
+ export interface PeerMetadata {
15
+ storageId?: StorageId
16
+ isEphemeral?: boolean
17
+ }
18
+
19
+ /** An interface representing some way to connect to other peers
20
+ *
21
+ * @remarks
22
+ * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
23
+ * Because the network may take some time to be ready the {@link Repo} will wait
24
+ * until the adapter emits a `ready` event before it starts trying to use it
25
+ */
26
+ export interface NetworkAdapterInterface extends EventEmitter<NetworkAdapterEvents> {
27
+ peerId?: PeerId
28
+ peerMetadata?: PeerMetadata
29
+
30
+ /** Called by the {@link Repo} to start the connection process
31
+ *
32
+ * @argument peerId - the peerId of this repo
33
+ * @argument peerMetadata - how this adapter should present itself to other peers
34
+ */
35
+ connect(peerId: PeerId, peerMetadata?: PeerMetadata): void
36
+
37
+ /** Called by the {@link Repo} to send a message to a peer
38
+ *
39
+ * @argument message - the message to send
40
+ */
41
+ send(message: Message): void
42
+
43
+ /** Called by the {@link Repo} to disconnect from the network */
44
+ disconnect(): void
45
+ }
46
+
47
+ // events & payloads
48
+
49
+ export interface NetworkAdapterEvents {
50
+ /** Emitted when the network is ready to be used */
51
+ ready: (payload: OpenPayload) => void
52
+
53
+ /** Emitted when the network is closed */
54
+ close: () => void
55
+
56
+ /** Emitted when the network adapter learns about a new peer */
57
+ "peer-candidate": (payload: PeerCandidatePayload) => void
58
+
59
+ /** Emitted when the network adapter learns that a peer has disconnected */
60
+ "peer-disconnected": (payload: PeerDisconnectedPayload) => void
61
+
62
+ /** Emitted when the network adapter receives a message from a peer */
63
+ message: (payload: Message) => void
64
+ }
65
+
66
+ export interface OpenPayload {
67
+ network: NetworkAdapterInterface
68
+ }
69
+
70
+ export interface PeerCandidatePayload {
71
+ peerId: PeerId
72
+ peerMetadata: PeerMetadata
73
+ }
74
+
75
+ export interface PeerDisconnectedPayload {
76
+ peerId: PeerId
77
+ }
@@ -2,10 +2,10 @@ import debug from "debug"
2
2
  import { EventEmitter } from "eventemitter3"
3
3
  import { PeerId, SessionId } from "../types.js"
4
4
  import type {
5
- NetworkAdapter,
5
+ NetworkAdapterInterface,
6
6
  PeerDisconnectedPayload,
7
7
  PeerMetadata,
8
- } from "./NetworkAdapter.js"
8
+ } from "./NetworkAdapterInterface.js"
9
9
  import {
10
10
  EphemeralMessage,
11
11
  MessageContents,
@@ -21,16 +21,16 @@ const getEphemeralMessageSource = (message: EphemeralMessage) =>
21
21
 
22
22
  export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
23
23
  #log: debug.Debugger
24
- #adaptersByPeer: Record<PeerId, NetworkAdapter> = {}
24
+ #adaptersByPeer: Record<PeerId, NetworkAdapterInterface> = {}
25
25
 
26
26
  #count = 0
27
27
  #sessionId: SessionId = Math.random().toString(36).slice(2) as SessionId
28
28
  #ephemeralSessionCounts: Record<EphemeralMessageSource, number> = {}
29
29
  #readyAdapterCount = 0
30
- #adapters: NetworkAdapter[] = []
30
+ #adapters: NetworkAdapterInterface[] = []
31
31
 
32
32
  constructor(
33
- adapters: NetworkAdapter[],
33
+ adapters: NetworkAdapterInterface[],
34
34
  public peerId = randomPeerId(),
35
35
  private peerMetadata: Promise<PeerMetadata>
36
36
  ) {
@@ -39,7 +39,7 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
39
39
  adapters.forEach(a => this.addNetworkAdapter(a))
40
40
  }
41
41
 
42
- addNetworkAdapter(networkAdapter: NetworkAdapter) {
42
+ addNetworkAdapter(networkAdapter: NetworkAdapterInterface) {
43
43
  this.#adapters.push(networkAdapter)
44
44
  networkAdapter.once("ready", () => {
45
45
  this.#readyAdapterCount++
@@ -105,11 +105,13 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
105
105
  })
106
106
  })
107
107
 
108
- this.peerMetadata.then(peerMetadata => {
109
- networkAdapter.connect(this.peerId, peerMetadata)
110
- }).catch(err => {
111
- this.#log("error connecting to network", err)
112
- })
108
+ this.peerMetadata
109
+ .then(peerMetadata => {
110
+ networkAdapter.connect(this.peerId, peerMetadata)
111
+ })
112
+ .catch(err => {
113
+ this.#log("error connecting to network", err)
114
+ })
113
115
  }
114
116
 
115
117
  send(message: MessageContents) {
@@ -1,12 +1,14 @@
1
+ import { StorageAdapterInterface } from "./StorageAdapterInterface.js"
1
2
  import { StorageKey, Chunk } from "./types.js"
2
3
 
3
4
  /** A storage adapter represents some way of storing binary data for a {@link Repo}
5
+ * @deprecated use {@link StorageAdapterInterface}
4
6
  *
5
7
  * @remarks
6
8
  * `StorageAdapter`s provide a key/value storage interface. The keys are arrays of strings
7
9
  * ({@link StorageKey}) and the values are binary blobs.
8
10
  */
9
- export abstract class StorageAdapter {
11
+ export abstract class StorageAdapter implements StorageAdapterInterface {
10
12
  /** Load the single value corresponding to `key` */
11
13
  abstract load(key: StorageKey): Promise<Uint8Array | undefined>
12
14
 
@@ -0,0 +1,34 @@
1
+ import { StorageKey, Chunk } from "./types.js"
2
+
3
+ /** A storage adapter represents some way of storing binary data for a {@link Repo}
4
+ *
5
+ * @remarks
6
+ * `StorageAdapter`s provide a key/value storage interface. The keys are arrays of strings
7
+ * ({@link StorageKey}) and the values are binary blobs.
8
+ */
9
+ export interface StorageAdapterInterface {
10
+ /** Load the single value corresponding to `key` */
11
+ load(key: StorageKey): Promise<Uint8Array | undefined>
12
+
13
+ /** Save the value `data` to the key `key` */
14
+ save(key: StorageKey, data: Uint8Array): Promise<void>
15
+
16
+ /** Remove the value corresponding to `key` */
17
+ remove(key: StorageKey): Promise<void>
18
+
19
+ /**
20
+ * Load all values with keys that start with `keyPrefix`.
21
+ *
22
+ * @remarks
23
+ * The `keyprefix` will match any key that starts with the given array. For example:
24
+ * - `[documentId, "incremental"]` will match all incremental saves
25
+ * - `[documentId]` will match all data for a given document.
26
+ *
27
+ * Be careful! `[documentId]` would also match something like `[documentId, "syncState"]`! We
28
+ * aren't using this yet but keep it in mind.)
29
+ */
30
+ loadRange(keyPrefix: StorageKey): Promise<Chunk[]>
31
+
32
+ /** Remove all values with keys that start with `keyPrefix` */
33
+ removeRange(keyPrefix: StorageKey): Promise<void>
34
+ }
@@ -3,7 +3,7 @@ import debug from "debug"
3
3
  import { headsAreSame } from "../helpers/headsAreSame.js"
4
4
  import { mergeArrays } from "../helpers/mergeArrays.js"
5
5
  import { type DocumentId } from "../types.js"
6
- import { StorageAdapter } from "./StorageAdapter.js"
6
+ import { StorageAdapterInterface } from "./StorageAdapterInterface.js"
7
7
  import { ChunkInfo, StorageKey, StorageId } from "./types.js"
8
8
  import { keyHash, headsHash } from "./keyHash.js"
9
9
  import { chunkTypeFromKey } from "./chunkTypeFromKey.js"
@@ -15,7 +15,7 @@ import * as Uuid from "uuid"
15
15
  */
16
16
  export class StorageSubsystem {
17
17
  /** The storage adapter to use for saving and loading documents */
18
- #storageAdapter: StorageAdapter
18
+ #storageAdapter: StorageAdapterInterface
19
19
 
20
20
  /** Record of the latest heads we've loaded or saved for each document */
21
21
  #storedHeads: Map<DocumentId, A.Heads> = new Map()
@@ -28,7 +28,7 @@ export class StorageSubsystem {
28
28
 
29
29
  #log = debug(`automerge-repo:storage-subsystem`)
30
30
 
31
- constructor(storageAdapter: StorageAdapter) {
31
+ constructor(storageAdapter: StorageAdapterInterface) {
32
32
  this.#storageAdapter = storageAdapter
33
33
  }
34
34
 
@@ -227,8 +227,8 @@ export class DocSynchronizer extends Synchronizer {
227
227
  }
228
228
 
229
229
  beginSync(peerIds: PeerId[]) {
230
- const newPeers = new Set(
231
- peerIds.filter(peerId => !this.#peers.includes(peerId))
230
+ const noPeersWithDocument = peerIds.every(
231
+ (peerId) => this.#peerDocumentStatuses[peerId] in ["unavailable", "wants"]
232
232
  )
233
233
 
234
234
  // At this point if we don't have anything in our storage, we need to use an empty doc to sync
@@ -242,7 +242,7 @@ export class DocSynchronizer extends Synchronizer {
242
242
  this.#checkDocUnavailable()
243
243
 
244
244
  const wasUnavailable = doc === undefined
245
- if (wasUnavailable && newPeers.size == 0) {
245
+ if (wasUnavailable && noPeersWithDocument) {
246
246
  return
247
247
  }
248
248
 
@@ -1,7 +1,7 @@
1
1
  import * as A from "@automerge/automerge/next"
2
2
  import assert from "assert"
3
3
  import { decode } from "cbor-x"
4
- import { describe, it } from "vitest"
4
+ import { describe, it, vi } from "vitest"
5
5
  import { generateAutomergeUrl, parseAutomergeUrl } from "../src/AutomergeUrl.js"
6
6
  import { eventPromise } from "../src/helpers/eventPromise.js"
7
7
  import { pause } from "../src/helpers/pause.js"
@@ -72,6 +72,29 @@ describe("DocHandle", () => {
72
72
  assert.equal(doc?.foo, "bar")
73
73
  })
74
74
 
75
+ /**
76
+ * Once there's a Repo#stop API this case should be covered in accompanying
77
+ * tests and the following test removed.
78
+ */
79
+ it("no pending timers after a document is loaded", async () => {
80
+ vi.useFakeTimers()
81
+ const timerCount = vi.getTimerCount()
82
+
83
+ const handle = new DocHandle<TestDoc>(TEST_ID)
84
+ assert.equal(handle.isReady(), false)
85
+
86
+ handle.doc()
87
+
88
+ assert(vi.getTimerCount() > timerCount)
89
+
90
+ // simulate loading from storage
91
+ handle.update(doc => docFromMockStorage(doc))
92
+
93
+ assert.equal(handle.isReady(), true)
94
+ assert.equal(vi.getTimerCount(), timerCount)
95
+ vi.useRealTimers()
96
+ })
97
+
75
98
  it("should block changes until ready()", async () => {
76
99
  const handle = new DocHandle<TestDoc>(TEST_ID)
77
100
 
package/test/Repo.test.ts CHANGED
@@ -3,7 +3,7 @@ import { MessageChannelNetworkAdapter } from "../../automerge-repo-network-messa
3
3
  import assert from "assert"
4
4
  import * as Uuid from "uuid"
5
5
  import { describe, expect, it } from "vitest"
6
- import { READY } from "../src/DocHandle.js"
6
+ import { HandleState, READY } from "../src/DocHandle.js"
7
7
  import { parseAutomergeUrl } from "../src/AutomergeUrl.js"
8
8
  import {
9
9
  generateAutomergeUrl,
@@ -1023,6 +1023,37 @@ describe("Repo", () => {
1023
1023
  })
1024
1024
  })
1025
1025
 
1026
+
1027
+ it('peer receives a document when connection is recovered', async () => {
1028
+ const alice = "alice" as PeerId;
1029
+ const bob = "bob" as PeerId;
1030
+ const [aliceAdapter, bobAdapter] = DummyNetworkAdapter.createConnectedPair();
1031
+ const aliceRepo = new Repo({
1032
+ network: [aliceAdapter],
1033
+ peerId: alice
1034
+ })
1035
+ const bobRepo = new Repo({
1036
+ network: [bobAdapter],
1037
+ peerId: bob
1038
+ })
1039
+
1040
+ const aliceDoc = aliceRepo.create();
1041
+ aliceDoc.change((doc: any) => doc.text = 'Hello world');
1042
+
1043
+ const bobDoc = bobRepo.find(aliceDoc.url);
1044
+ bobDoc.unavailable()
1045
+ await bobDoc.whenReady([HandleState.UNAVAILABLE]);
1046
+
1047
+ aliceAdapter.peerCandidate(bob);
1048
+ // Bob isn't yet connected to Alice and can't respond to her sync message
1049
+ await pause(100);
1050
+ bobAdapter.peerCandidate(alice);
1051
+
1052
+ await bobDoc.whenReady([HandleState.READY]);
1053
+
1054
+ assert.equal(bobDoc.isReady(), true);
1055
+ });
1056
+
1026
1057
  describe("with peers (mesh network)", () => {
1027
1058
  const setup = async () => {
1028
1059
  // Set up three repos; connect Alice to Bob, Bob to Charlie, and Alice to Charlie
@@ -1,21 +1,53 @@
1
- import { NetworkAdapter } from "../../src/index.js"
1
+ import { pause } from "../../src/helpers/pause.js";
2
+ import { Message, NetworkAdapter, PeerId } from "../../src/index.js"
2
3
 
3
4
  export class DummyNetworkAdapter extends NetworkAdapter {
4
5
  #startReady: boolean
6
+ #sendMessage?: SendMessageFn;
5
7
 
6
- constructor({ startReady = true }: Options = {}) {
8
+ constructor(opts: Options = {startReady: true}) {
7
9
  super()
8
- this.#startReady = startReady
10
+ this.#startReady = opts.startReady;
11
+ this.#sendMessage = opts.sendMessage;
9
12
  }
10
- send() {}
13
+
11
14
  connect(_: string) {
12
15
  if (this.#startReady) {
13
16
  this.emit("ready", { network: this })
14
17
  }
15
18
  }
19
+
16
20
  disconnect() {}
21
+
22
+ peerCandidate(peerId: PeerId) {
23
+ this.emit('peer-candidate', { peerId, peerMetadata: {} });
24
+ }
25
+
26
+ override send(message: Message) {
27
+ this.#sendMessage?.(message);
28
+ }
29
+
30
+ receive(message: Message) {
31
+ this.emit('message', message);
32
+ }
33
+
34
+ static createConnectedPair() {
35
+ const adapter1: DummyNetworkAdapter = new DummyNetworkAdapter({
36
+ startReady: true,
37
+ sendMessage: (message: Message) => pause(10).then(() => adapter2.receive(message)),
38
+ });
39
+ const adapter2: DummyNetworkAdapter = new DummyNetworkAdapter({
40
+ startReady: true,
41
+ sendMessage: (message: Message) => pause(10).then(() => adapter1.receive(message)),
42
+ });
43
+
44
+ return [adapter1, adapter2];
45
+ }
17
46
  }
18
47
 
48
+ type SendMessageFn = (message: Message) => void;
49
+
19
50
  type Options = {
20
- startReady?: boolean
51
+ startReady?: boolean;
52
+ sendMessage?: SendMessageFn;
21
53
  }