@automerge/automerge-repo 1.1.1 → 1.1.3

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.
package/README.md CHANGED
@@ -52,7 +52,7 @@ A `Repo` exposes these methods:
52
52
  - `.on("document", ({handle: DocHandle}) => void)`
53
53
  Registers a callback to be fired each time a new document is loaded or created.
54
54
  - `.on("delete-document", ({handle: DocHandle}) => void)`
55
- Registers a callback to be fired each time a new document is loaded or created.
55
+ Registers a callback to be fired each time a new document is deleted.
56
56
 
57
57
  A `DocHandle` is a wrapper around an `Automerge.Doc`. Its primary function is to dispatch changes to
58
58
  the document.
package/dist/DocHandle.js CHANGED
@@ -315,7 +315,7 @@ export class DocHandle//
315
315
  payload: {
316
316
  callback: (doc) => {
317
317
  const result = A.changeAt(doc, heads, options, callback);
318
- resultHeads = result.newHeads;
318
+ resultHeads = result.newHeads || undefined;
319
319
  return result.newDoc;
320
320
  },
321
321
  },
package/dist/Repo.js CHANGED
@@ -156,7 +156,7 @@ export class Repo extends EventEmitter {
156
156
  const heads = handle.getRemoteHeads(storageId);
157
157
  const haveHeadsChanged = message.syncState.theirHeads &&
158
158
  (!heads || !headsAreSame(heads, message.syncState.theirHeads));
159
- if (haveHeadsChanged) {
159
+ if (haveHeadsChanged && message.syncState.theirHeads) {
160
160
  handle.setRemoteHeads(storageId, message.syncState.theirHeads);
161
161
  if (storageId && this.#remoteHeadsGossipingEnabled) {
162
162
  this.#remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(message.documentId, storageId, message.syncState.theirHeads);
@@ -1,2 +1,3 @@
1
+ import { Heads } from "@automerge/automerge/next";
1
2
  export declare const headsAreSame: (a: Heads, b: Heads) => boolean;
2
3
  //# sourceMappingURL=headsAreSame.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"headsAreSame.d.ts","sourceRoot":"","sources":["../../src/helpers/headsAreSame.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,iCAExB,CAAA"}
1
+ {"version":3,"file":"headsAreSame.d.ts","sourceRoot":"","sources":["../../src/helpers/headsAreSame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AAGjD,eAAO,MAAM,YAAY,iCAExB,CAAA"}
@@ -4,12 +4,14 @@ import { PeerId } from "../types.js";
4
4
  import { Message } from "./messages.js";
5
5
  import { NetworkAdapterInterface } from "./NetworkAdapterInterface.js";
6
6
  /** An interface representing some way to connect to other peers
7
- * @deprecated use {@link NetworkAdapterInterface}
8
7
  *
9
8
  * @remarks
10
9
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
11
10
  * Because the network may take some time to be ready the {@link Repo} will wait
12
11
  * until the adapter emits a `ready` event before it starts trying to use it
12
+ *
13
+ * This utility class can be used as a base to build a custom network adapter. It
14
+ * is most useful as a simple way to add the necessary event emitter functionality
13
15
  */
14
16
  export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> implements NetworkAdapterInterface {
15
17
  peerId?: PeerId;
@@ -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,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
+ {"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;;;;;;;;;GASG;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,12 +1,14 @@
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}
5
4
  *
6
5
  * @remarks
7
6
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
8
7
  * Because the network may take some time to be ready the {@link Repo} will wait
9
8
  * until the adapter emits a `ready` event before it starts trying to use it
9
+ *
10
+ * This utility class can be used as a base to build a custom network adapter. It
11
+ * is most useful as a simple way to add the necessary event emitter functionality
10
12
  */
11
13
  export class NetworkAdapter extends EventEmitter {
12
14
  peerId;
@@ -18,6 +18,10 @@ export interface PeerMetadata {
18
18
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
19
19
  * Because the network may take some time to be ready the {@link Repo} will wait
20
20
  * until the adapter emits a `ready` event before it starts trying to use it
21
+ *
22
+ * The {@link NetworkAdapter} is an abstract class that can be used as a base to build a
23
+ * custom network adapter. It is most useful as a simple way to add the necessary event
24
+ * emitter functionality
21
25
  */
22
26
  export interface NetworkAdapterInterface extends EventEmitter<NetworkAdapterEvents> {
23
27
  peerId?: PeerId;
@@ -1 +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"}
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;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBACf,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC1C,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"}
@@ -6,7 +6,7 @@ import { Synchronizer } from "./Synchronizer.js";
6
6
  type PeerDocumentStatus = "unknown" | "has" | "unavailable" | "wants";
7
7
  interface DocSynchronizerConfig {
8
8
  handle: DocHandle<unknown>;
9
- onLoadSyncState?: (peerId: PeerId) => A.SyncState | undefined;
9
+ onLoadSyncState?: (peerId: PeerId) => Promise<A.SyncState | undefined>;
10
10
  }
11
11
  /**
12
12
  * DocSynchronizer takes a handle to an Automerge document, and receives & dispatches sync messages
@@ -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;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"}
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,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;CACvE;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automerge/automerge-repo",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
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": "7e0681014b8c5f672e2abc2a653a954ccb6d7aba"
58
+ "gitHead": "f59ba3612d1110003e2365fe0fe5a799539f1b59"
59
59
  }
package/src/DocHandle.ts CHANGED
@@ -383,7 +383,7 @@ export class DocHandle<T> //
383
383
  payload: {
384
384
  callback: (doc: A.Doc<T>) => {
385
385
  const result = A.changeAt(doc, heads, options, callback)
386
- resultHeads = result.newHeads
386
+ resultHeads = result.newHeads || undefined
387
387
  return result.newDoc
388
388
  },
389
389
  },
package/src/Repo.ts CHANGED
@@ -214,7 +214,7 @@ export class Repo extends EventEmitter<RepoEvents> {
214
214
  message.syncState.theirHeads &&
215
215
  (!heads || !headsAreSame(heads, message.syncState.theirHeads))
216
216
 
217
- if (haveHeadsChanged) {
217
+ if (haveHeadsChanged && message.syncState.theirHeads) {
218
218
  handle.setRemoteHeads(storageId, message.syncState.theirHeads)
219
219
 
220
220
  if (storageId && this.#remoteHeadsGossipingEnabled) {
@@ -7,12 +7,14 @@ import { Message } from "./messages.js"
7
7
  import { NetworkAdapterInterface } from "./NetworkAdapterInterface.js"
8
8
 
9
9
  /** An interface representing some way to connect to other peers
10
- * @deprecated use {@link NetworkAdapterInterface}
11
10
  *
12
11
  * @remarks
13
12
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
14
13
  * Because the network may take some time to be ready the {@link Repo} will wait
15
14
  * until the adapter emits a `ready` event before it starts trying to use it
15
+ *
16
+ * This utility class can be used as a base to build a custom network adapter. It
17
+ * is most useful as a simple way to add the necessary event emitter functionality
16
18
  */
17
19
  export abstract class NetworkAdapter
18
20
  extends EventEmitter<NetworkAdapterEvents>
@@ -22,8 +22,13 @@ export interface PeerMetadata {
22
22
  * The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
23
23
  * Because the network may take some time to be ready the {@link Repo} will wait
24
24
  * until the adapter emits a `ready` event before it starts trying to use it
25
+ *
26
+ * The {@link NetworkAdapter} is an abstract class that can be used as a base to build a
27
+ * custom network adapter. It is most useful as a simple way to add the necessary event
28
+ * emitter functionality
25
29
  */
26
- export interface NetworkAdapterInterface extends EventEmitter<NetworkAdapterEvents> {
30
+ export interface NetworkAdapterInterface
31
+ extends EventEmitter<NetworkAdapterEvents> {
27
32
  peerId?: PeerId
28
33
  peerMetadata?: PeerMetadata
29
34
 
@@ -30,7 +30,7 @@ type PendingMessage = {
30
30
 
31
31
  interface DocSynchronizerConfig {
32
32
  handle: DocHandle<unknown>
33
- onLoadSyncState?: (peerId: PeerId) => A.SyncState | undefined
33
+ onLoadSyncState?: (peerId: PeerId) => Promise<A.SyncState | undefined>
34
34
  }
35
35
 
36
36
  /**
package/test/Repo.test.ts CHANGED
@@ -461,6 +461,80 @@ describe("Repo", () => {
461
461
  })
462
462
 
463
463
  describe("with peers (linear network)", async () => {
464
+ it("n-peers connected in a line", async () => {
465
+ const createNConnectedRepos = async (
466
+ numberOfPeers: number,
467
+ latency?: number
468
+ ) => {
469
+ const networkAdapters: DummyNetworkAdapter[][] = []
470
+ const repos: Repo[] = []
471
+ const networkReady: Promise<void>[] = []
472
+
473
+ // Create n repos and connect them in a line.
474
+ for (let idx = 0; idx < numberOfPeers; idx++) {
475
+ const network = []
476
+
477
+ const pair = DummyNetworkAdapter.createConnectedPair({ latency })
478
+ networkAdapters.push(pair)
479
+
480
+ if (idx > 0) {
481
+ network.push(networkAdapters[idx - 1][1])
482
+ networkReady.push(
483
+ eventPromise(networkAdapters[idx - 1][1], "ready")
484
+ )
485
+ }
486
+
487
+ if (idx < numberOfPeers - 1) {
488
+ network.push(pair[0])
489
+ networkReady.push(eventPromise(pair[0], "ready"))
490
+ }
491
+
492
+ const repo = new Repo({
493
+ network,
494
+ storage: new DummyStorageAdapter(),
495
+ peerId: `peer-${idx}` as PeerId,
496
+ sharePolicy: async () => true,
497
+ })
498
+ repos.push(repo)
499
+ }
500
+
501
+ await Promise.all(networkReady)
502
+
503
+ const connectedPromise = Promise.all(
504
+ repos.map(repo => eventPromise(repo.networkSubsystem, "peer"))
505
+ )
506
+
507
+ // Initialize the network.
508
+ for (let idx = 0; idx < numberOfPeers; idx++) {
509
+ if (idx > 0) {
510
+ networkAdapters[idx - 1][1].peerCandidate(
511
+ `peer-${idx - 1}` as PeerId
512
+ )
513
+ }
514
+ if (idx < numberOfPeers - 1) {
515
+ networkAdapters[idx][0].peerCandidate(`peer-${idx + 1}` as PeerId)
516
+ }
517
+ }
518
+
519
+ await connectedPromise
520
+
521
+ return { repos }
522
+ }
523
+
524
+ const numberOfPeers = 10
525
+ const { repos } = await createNConnectedRepos(numberOfPeers, 10)
526
+
527
+ const handle0 = repos[0].create()
528
+ handle0.change((d: any) => {
529
+ d.foo = "bar"
530
+ })
531
+
532
+ const handleN = repos[numberOfPeers - 1].find<TestDoc>(handle0.url)
533
+
534
+ await handleN.whenReady()
535
+ assert.deepStrictEqual(handleN.docSync(), { foo: "bar" })
536
+ })
537
+
464
538
  const setup = async ({
465
539
  connectAlice = true,
466
540
  isCharlieEphemeral = false,
@@ -1023,36 +1097,35 @@ describe("Repo", () => {
1023
1097
  })
1024
1098
  })
1025
1099
 
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();
1100
+ it("peer receives a document when connection is recovered", async () => {
1101
+ const alice = "alice" as PeerId
1102
+ const bob = "bob" as PeerId
1103
+ const [aliceAdapter, bobAdapter] = DummyNetworkAdapter.createConnectedPair()
1031
1104
  const aliceRepo = new Repo({
1032
1105
  network: [aliceAdapter],
1033
- peerId: alice
1106
+ peerId: alice,
1034
1107
  })
1035
1108
  const bobRepo = new Repo({
1036
1109
  network: [bobAdapter],
1037
- peerId: bob
1110
+ peerId: bob,
1038
1111
  })
1039
1112
 
1040
- const aliceDoc = aliceRepo.create();
1041
- aliceDoc.change((doc: any) => doc.text = 'Hello world');
1113
+ const aliceDoc = aliceRepo.create()
1114
+ aliceDoc.change((doc: any) => (doc.text = "Hello world"))
1042
1115
 
1043
- const bobDoc = bobRepo.find(aliceDoc.url);
1116
+ const bobDoc = bobRepo.find(aliceDoc.url)
1044
1117
  bobDoc.unavailable()
1045
- await bobDoc.whenReady([HandleState.UNAVAILABLE]);
1118
+ await bobDoc.whenReady([HandleState.UNAVAILABLE])
1046
1119
 
1047
- aliceAdapter.peerCandidate(bob);
1120
+ aliceAdapter.peerCandidate(bob)
1048
1121
  // Bob isn't yet connected to Alice and can't respond to her sync message
1049
- await pause(100);
1050
- bobAdapter.peerCandidate(alice);
1122
+ await pause(100)
1123
+ bobAdapter.peerCandidate(alice)
1051
1124
 
1052
- await bobDoc.whenReady([HandleState.READY]);
1125
+ await bobDoc.whenReady([HandleState.READY])
1053
1126
 
1054
- assert.equal(bobDoc.isReady(), true);
1055
- });
1127
+ assert.equal(bobDoc.isReady(), true)
1128
+ })
1056
1129
 
1057
1130
  describe("with peers (mesh network)", () => {
1058
1131
  const setup = async () => {
@@ -11,7 +11,8 @@ export class DummyNetworkAdapter extends NetworkAdapter {
11
11
  this.#sendMessage = opts.sendMessage;
12
12
  }
13
13
 
14
- connect(_: string) {
14
+ connect(peerId: PeerId) {
15
+ this.peerId = peerId;
15
16
  if (this.#startReady) {
16
17
  this.emit("ready", { network: this })
17
18
  }
@@ -31,14 +32,14 @@ export class DummyNetworkAdapter extends NetworkAdapter {
31
32
  this.emit('message', message);
32
33
  }
33
34
 
34
- static createConnectedPair() {
35
+ static createConnectedPair({ latency = 10 }: { latency?: number} = {}) {
35
36
  const adapter1: DummyNetworkAdapter = new DummyNetworkAdapter({
36
37
  startReady: true,
37
- sendMessage: (message: Message) => pause(10).then(() => adapter2.receive(message)),
38
+ sendMessage: (message: Message) => pause(latency).then(() => adapter2.receive(message)),
38
39
  });
39
40
  const adapter2: DummyNetworkAdapter = new DummyNetworkAdapter({
40
41
  startReady: true,
41
- sendMessage: (message: Message) => pause(10).then(() => adapter1.receive(message)),
42
+ sendMessage: (message: Message) => pause(latency).then(() => adapter1.receive(message)),
42
43
  });
43
44
 
44
45
  return [adapter1, adapter2];
@@ -1,6 +1,6 @@
1
- import { Chunk, StorageAdapter, type StorageKey } from "../../src/index.js"
1
+ import { Chunk, StorageAdapterInterface, type StorageKey } from "../../src/index.js"
2
2
 
3
- export class DummyStorageAdapter implements StorageAdapter {
3
+ export class DummyStorageAdapter implements StorageAdapterInterface {
4
4
  #data: Record<string, Uint8Array> = {}
5
5
 
6
6
  #keyToString(key: string[]): string {