@automerge/automerge-repo 1.0.17 → 1.0.19
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/dist/DocHandle.d.ts +16 -3
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +20 -13
- package/dist/Repo.d.ts +2 -0
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +17 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/network/messages.d.ts +7 -0
- package/dist/network/messages.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.d.ts +3 -1
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +10 -0
- package/dist/storage/chunkTypeFromKey.d.ts +1 -2
- package/dist/storage/chunkTypeFromKey.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.d.ts +2 -0
- package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.js +14 -1
- package/dist/synchronizer/DocSynchronizer.d.ts +6 -2
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +119 -76
- package/dist/synchronizer/Synchronizer.d.ts +2 -1
- package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
- package/package.json +3 -5
- package/src/DocHandle.ts +32 -13
- package/src/Repo.ts +23 -6
- package/src/index.ts +1 -0
- package/src/network/messages.ts +8 -0
- package/src/storage/StorageSubsystem.ts +20 -2
- package/src/storage/chunkTypeFromKey.ts +1 -2
- package/src/synchronizer/CollectionSynchronizer.ts +19 -1
- package/src/synchronizer/DocSynchronizer.ts +168 -94
- package/src/synchronizer/Synchronizer.ts +6 -1
- package/test/DocHandle.test.ts +19 -2
- package/test/DocSynchronizer.test.ts +47 -16
- package/test/Repo.test.ts +159 -4
- package/test/StorageSubsystem.test.ts +30 -2
package/test/Repo.test.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { next as A } from "@automerge/automerge"
|
|
1
2
|
import { MessageChannelNetworkAdapter } from "@automerge/automerge-repo-network-messagechannel"
|
|
2
3
|
import assert from "assert"
|
|
3
4
|
import * as Uuid from "uuid"
|
|
4
5
|
import { describe, it } from "vitest"
|
|
6
|
+
import { DocHandleRemoteHeadsPayload, READY } from "../src/DocHandle.js"
|
|
5
7
|
import { parseAutomergeUrl } from "../src/AutomergeUrl.js"
|
|
6
|
-
import { READY } from "../src/DocHandle.js"
|
|
7
8
|
import {
|
|
8
9
|
generateAutomergeUrl,
|
|
9
10
|
stringifyAutomergeUrl,
|
|
@@ -425,24 +426,31 @@ describe("Repo", () => {
|
|
|
425
426
|
|
|
426
427
|
const aliceNetworkAdapter = new MessageChannelNetworkAdapter(ab)
|
|
427
428
|
|
|
429
|
+
const alice = "alice" as PeerId
|
|
428
430
|
const aliceRepo = new Repo({
|
|
429
431
|
network: connectAlice ? [aliceNetworkAdapter] : [],
|
|
430
|
-
peerId:
|
|
432
|
+
peerId: alice,
|
|
431
433
|
sharePolicy,
|
|
432
434
|
})
|
|
433
435
|
|
|
436
|
+
const bob = "bob" as PeerId
|
|
437
|
+
const bobStorage = new DummyStorageAdapter()
|
|
434
438
|
const bobRepo = new Repo({
|
|
439
|
+
storage: bobStorage,
|
|
435
440
|
network: [
|
|
436
441
|
new MessageChannelNetworkAdapter(ba),
|
|
437
442
|
new MessageChannelNetworkAdapter(bc),
|
|
438
443
|
],
|
|
439
|
-
peerId:
|
|
444
|
+
peerId: bob,
|
|
440
445
|
sharePolicy,
|
|
441
446
|
})
|
|
442
447
|
|
|
448
|
+
const charlie = "charlie" as PeerId
|
|
449
|
+
const charlieStorage = new DummyStorageAdapter()
|
|
443
450
|
const charlieRepo = new Repo({
|
|
451
|
+
storage: charlieStorage,
|
|
444
452
|
network: [new MessageChannelNetworkAdapter(cb)],
|
|
445
|
-
peerId:
|
|
453
|
+
peerId: charlie,
|
|
446
454
|
})
|
|
447
455
|
|
|
448
456
|
const teardown = () => {
|
|
@@ -488,8 +496,13 @@ describe("Repo", () => {
|
|
|
488
496
|
])
|
|
489
497
|
|
|
490
498
|
return {
|
|
499
|
+
alice,
|
|
491
500
|
aliceRepo,
|
|
501
|
+
bob,
|
|
502
|
+
bobStorage,
|
|
492
503
|
bobRepo,
|
|
504
|
+
charlie,
|
|
505
|
+
charlieStorage,
|
|
493
506
|
charlieRepo,
|
|
494
507
|
aliceHandle,
|
|
495
508
|
notForCharlie,
|
|
@@ -541,6 +554,9 @@ describe("Repo", () => {
|
|
|
541
554
|
const handle = charlieRepo.find<TestDoc>(
|
|
542
555
|
stringifyAutomergeUrl({ documentId: notForCharlie })
|
|
543
556
|
)
|
|
557
|
+
|
|
558
|
+
await pause(50)
|
|
559
|
+
|
|
544
560
|
const doc = await handle.doc()
|
|
545
561
|
|
|
546
562
|
assert.deepStrictEqual(doc, { foo: "baz" })
|
|
@@ -554,6 +570,9 @@ describe("Repo", () => {
|
|
|
554
570
|
const handle = charlieRepo.find<TestDoc>(
|
|
555
571
|
stringifyAutomergeUrl({ documentId: notForBob })
|
|
556
572
|
)
|
|
573
|
+
|
|
574
|
+
await pause(50)
|
|
575
|
+
|
|
557
576
|
const doc = await handle.doc()
|
|
558
577
|
assert.deepStrictEqual(doc, { foo: "bap" })
|
|
559
578
|
|
|
@@ -768,6 +787,142 @@ describe("Repo", () => {
|
|
|
768
787
|
await charliePromise
|
|
769
788
|
teardown()
|
|
770
789
|
})
|
|
790
|
+
|
|
791
|
+
it("should save sync state of other peers", async () => {
|
|
792
|
+
const { bobRepo, teardown, charlie } = await setup({
|
|
793
|
+
connectAlice: false,
|
|
794
|
+
})
|
|
795
|
+
|
|
796
|
+
const bobHandle = bobRepo.create<TestDoc>()
|
|
797
|
+
bobHandle.change(d => {
|
|
798
|
+
d.foo = "bar"
|
|
799
|
+
})
|
|
800
|
+
|
|
801
|
+
await pause(200)
|
|
802
|
+
|
|
803
|
+
// bob should store the sync state of charlie
|
|
804
|
+
const storedSyncState = await bobRepo.storageSubsystem.loadSyncState(
|
|
805
|
+
bobHandle.documentId,
|
|
806
|
+
charlie
|
|
807
|
+
)
|
|
808
|
+
const docHeads = A.getHeads(bobHandle.docSync())
|
|
809
|
+
assert.deepStrictEqual(storedSyncState.sharedHeads, docHeads)
|
|
810
|
+
|
|
811
|
+
teardown()
|
|
812
|
+
})
|
|
813
|
+
|
|
814
|
+
it("should load sync state from storage", async () => {
|
|
815
|
+
const { bobRepo, teardown, charlie, charlieRepo, bobStorage, bob } =
|
|
816
|
+
await setup({
|
|
817
|
+
connectAlice: false,
|
|
818
|
+
})
|
|
819
|
+
|
|
820
|
+
// create a new doc and count sync messages
|
|
821
|
+
const bobHandle = bobRepo.create<TestDoc>()
|
|
822
|
+
bobHandle.change(d => {
|
|
823
|
+
d.foo = "bar"
|
|
824
|
+
})
|
|
825
|
+
let bobSyncMessages = 0
|
|
826
|
+
bobRepo.networkSubsystem.on("message", () => {
|
|
827
|
+
bobSyncMessages++
|
|
828
|
+
})
|
|
829
|
+
await pause(500)
|
|
830
|
+
|
|
831
|
+
// repo has no stored sync state for charlie so we should see two sync messages
|
|
832
|
+
assert.strictEqual(bobSyncMessages, 2)
|
|
833
|
+
|
|
834
|
+
// setup new repo which uses bob's storage
|
|
835
|
+
const bob2Repo = new Repo({
|
|
836
|
+
storage: bobStorage,
|
|
837
|
+
network: [],
|
|
838
|
+
peerId: "bob-2" as PeerId,
|
|
839
|
+
})
|
|
840
|
+
|
|
841
|
+
// connnect it with charlie
|
|
842
|
+
const channel = new MessageChannel()
|
|
843
|
+
bob2Repo.networkSubsystem.addNetworkAdapter(
|
|
844
|
+
new MessageChannelNetworkAdapter(channel.port2)
|
|
845
|
+
)
|
|
846
|
+
charlieRepo.networkSubsystem.addNetworkAdapter(
|
|
847
|
+
new MessageChannelNetworkAdapter(channel.port1)
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
// lookup doc we've previously created and count the messages
|
|
851
|
+
bob2Repo.find(bobHandle.documentId)
|
|
852
|
+
let bob2SyncMessages = 0
|
|
853
|
+
bob2Repo.networkSubsystem.on("message", m => {
|
|
854
|
+
bob2SyncMessages++
|
|
855
|
+
})
|
|
856
|
+
await pause(100)
|
|
857
|
+
|
|
858
|
+
// repo has stored sync state for charlie so we should see one sync messages
|
|
859
|
+
assert.strictEqual(bob2SyncMessages, 1)
|
|
860
|
+
|
|
861
|
+
channel.port1.close()
|
|
862
|
+
teardown()
|
|
863
|
+
})
|
|
864
|
+
|
|
865
|
+
it("should report the remote heads when they change", async () => {
|
|
866
|
+
const { bobRepo, charlieRepo, teardown } = await setup({
|
|
867
|
+
connectAlice: false,
|
|
868
|
+
})
|
|
869
|
+
|
|
870
|
+
const handle = bobRepo.create<TestDoc>()
|
|
871
|
+
handle.change(d => {
|
|
872
|
+
d.foo = "bar"
|
|
873
|
+
})
|
|
874
|
+
|
|
875
|
+
// pause to let the sync happen
|
|
876
|
+
await pause(50)
|
|
877
|
+
|
|
878
|
+
const nextRemoteHeadsPromise = new Promise<{
|
|
879
|
+
peerId: PeerId
|
|
880
|
+
heads: A.Heads
|
|
881
|
+
}>(resolve => {
|
|
882
|
+
handle.on("remote-heads", ({ peerId, heads }) => {
|
|
883
|
+
resolve({ peerId, heads })
|
|
884
|
+
})
|
|
885
|
+
})
|
|
886
|
+
|
|
887
|
+
const charlieHandle = charlieRepo.find<TestDoc>(handle.url)
|
|
888
|
+
await charlieHandle.whenReady()
|
|
889
|
+
|
|
890
|
+
// make a change on charlie
|
|
891
|
+
charlieHandle.change(d => {
|
|
892
|
+
d.foo = "baz"
|
|
893
|
+
})
|
|
894
|
+
|
|
895
|
+
// pause to let the sync happen
|
|
896
|
+
await pause(100)
|
|
897
|
+
|
|
898
|
+
const charlieHeads = A.getHeads(charlieHandle.docSync())
|
|
899
|
+
const bobHeads = A.getHeads(handle.docSync())
|
|
900
|
+
|
|
901
|
+
assert.deepStrictEqual(charlieHeads, bobHeads)
|
|
902
|
+
|
|
903
|
+
const nextRemoteHeads = await nextRemoteHeadsPromise
|
|
904
|
+
assert.deepStrictEqual(nextRemoteHeads.peerId, "charlie")
|
|
905
|
+
assert.deepStrictEqual(nextRemoteHeads.heads, charlieHeads)
|
|
906
|
+
|
|
907
|
+
assert.deepStrictEqual(
|
|
908
|
+
handle.getRemoteHeads("charlie" as PeerId),
|
|
909
|
+
A.getHeads(charlieHandle.docSync())
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
teardown()
|
|
913
|
+
})
|
|
914
|
+
|
|
915
|
+
it("can report the connected peers", async () => {
|
|
916
|
+
const { bobRepo, charlieRepo, teardown } = await setup()
|
|
917
|
+
|
|
918
|
+
// pause to let the connections happen
|
|
919
|
+
await pause(1)
|
|
920
|
+
|
|
921
|
+
assert.deepStrictEqual(bobRepo.peers, ["alice", "charlie"])
|
|
922
|
+
assert.deepStrictEqual(charlieRepo.peers, ["bob"])
|
|
923
|
+
|
|
924
|
+
teardown()
|
|
925
|
+
})
|
|
771
926
|
})
|
|
772
927
|
|
|
773
928
|
describe("with peers (mesh network)", () => {
|
|
@@ -6,10 +6,9 @@ import os from "os"
|
|
|
6
6
|
import path from "path"
|
|
7
7
|
import { describe, it } from "vitest"
|
|
8
8
|
import { generateAutomergeUrl, parseAutomergeUrl } from "../src/AutomergeUrl.js"
|
|
9
|
+
import { PeerId, cbor } from "../src/index.js"
|
|
9
10
|
import { StorageSubsystem } from "../src/storage/StorageSubsystem.js"
|
|
10
11
|
import { DummyStorageAdapter } from "./helpers/DummyStorageAdapter.js"
|
|
11
|
-
import { cbor } from "../src/index.js"
|
|
12
|
-
import { pause } from "../src/helpers/pause.js"
|
|
13
12
|
|
|
14
13
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "automerge-repo-tests"))
|
|
15
14
|
|
|
@@ -176,6 +175,35 @@ describe("StorageSubsystem", () => {
|
|
|
176
175
|
assert.equal(reloadedValue2, undefined)
|
|
177
176
|
})
|
|
178
177
|
})
|
|
178
|
+
|
|
179
|
+
describe("sync state", () => {
|
|
180
|
+
it("stores and retrieve sync state", async () => {
|
|
181
|
+
const storage = new StorageSubsystem(adapter)
|
|
182
|
+
|
|
183
|
+
const { documentId } = parseAutomergeUrl(generateAutomergeUrl())
|
|
184
|
+
const syncState = A.initSyncState()
|
|
185
|
+
const bob = "bob" as PeerId
|
|
186
|
+
|
|
187
|
+
const rawSyncState = A.decodeSyncState(A.encodeSyncState(syncState))
|
|
188
|
+
|
|
189
|
+
await storage.saveSyncState(documentId, bob, syncState)
|
|
190
|
+
const loadedSyncState = await storage.loadSyncState(documentId, bob)
|
|
191
|
+
assert.deepStrictEqual(loadedSyncState, rawSyncState)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it("delete sync state if document is deleted", async () => {
|
|
195
|
+
const storage = new StorageSubsystem(adapter)
|
|
196
|
+
|
|
197
|
+
const { documentId } = parseAutomergeUrl(generateAutomergeUrl())
|
|
198
|
+
const syncState = A.initSyncState()
|
|
199
|
+
const bob = "bob" as PeerId
|
|
200
|
+
|
|
201
|
+
await storage.saveSyncState(documentId, bob, syncState)
|
|
202
|
+
await storage.removeDoc(documentId)
|
|
203
|
+
const loadedSyncState = await storage.loadSyncState(documentId, bob)
|
|
204
|
+
assert.strictEqual(loadedSyncState, undefined)
|
|
205
|
+
})
|
|
206
|
+
})
|
|
179
207
|
})
|
|
180
208
|
})
|
|
181
209
|
})
|