@automerge/automerge-repo 1.1.4 → 1.1.8
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 +3 -22
- package/dist/DocHandle.d.ts +124 -100
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +239 -231
- package/dist/Repo.d.ts +10 -3
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +22 -1
- package/dist/helpers/arraysAreEqual.d.ts.map +1 -1
- package/dist/helpers/debounce.d.ts.map +1 -1
- package/dist/helpers/tests/network-adapter-tests.d.ts +1 -1
- package/dist/helpers/tests/network-adapter-tests.d.ts.map +1 -1
- package/dist/helpers/tests/network-adapter-tests.js +2 -2
- package/dist/helpers/tests/storage-adapter-tests.d.ts +7 -0
- package/dist/helpers/tests/storage-adapter-tests.d.ts.map +1 -0
- package/dist/helpers/tests/storage-adapter-tests.js +128 -0
- package/dist/helpers/throttle.d.ts.map +1 -1
- package/dist/helpers/withTimeout.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/synchronizer/DocSynchronizer.js +1 -1
- package/package.json +4 -4
- package/src/DocHandle.ts +325 -375
- package/src/Repo.ts +35 -8
- package/src/helpers/tests/network-adapter-tests.ts +4 -2
- package/src/helpers/tests/storage-adapter-tests.ts +193 -0
- package/src/index.ts +43 -0
- package/src/synchronizer/DocSynchronizer.ts +1 -1
- package/test/CollectionSynchronizer.test.ts +1 -3
- package/test/DocHandle.test.ts +19 -1
- package/test/DocSynchronizer.test.ts +1 -4
- package/test/DummyStorageAdapter.test.ts +11 -0
- package/test/Repo.test.ts +179 -53
- package/test/helpers/DummyNetworkAdapter.ts +20 -18
- package/test/helpers/DummyStorageAdapter.ts +5 -1
- package/test/remoteHeads.test.ts +1 -1
- package/tsconfig.json +1 -0
package/test/Repo.test.ts
CHANGED
|
@@ -3,7 +3,6 @@ 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 { HandleState, READY } from "../src/DocHandle.js"
|
|
7
6
|
import { parseAutomergeUrl } from "../src/AutomergeUrl.js"
|
|
8
7
|
import {
|
|
9
8
|
generateAutomergeUrl,
|
|
@@ -29,14 +28,12 @@ import {
|
|
|
29
28
|
} from "./helpers/generate-large-object.js"
|
|
30
29
|
import { getRandomItem } from "./helpers/getRandomItem.js"
|
|
31
30
|
import { TestDoc } from "./types.js"
|
|
32
|
-
import { StorageId } from "../src/storage/types.js"
|
|
31
|
+
import { StorageId, StorageKey } from "../src/storage/types.js"
|
|
33
32
|
|
|
34
33
|
describe("Repo", () => {
|
|
35
34
|
describe("constructor", () => {
|
|
36
|
-
it("can be instantiated without
|
|
37
|
-
const repo = new Repo(
|
|
38
|
-
network: [],
|
|
39
|
-
})
|
|
35
|
+
it("can be instantiated without any configuration", () => {
|
|
36
|
+
const repo = new Repo()
|
|
40
37
|
expect(repo).toBeInstanceOf(Repo)
|
|
41
38
|
})
|
|
42
39
|
})
|
|
@@ -126,8 +123,7 @@ describe("Repo", () => {
|
|
|
126
123
|
})
|
|
127
124
|
const v = await handle.doc()
|
|
128
125
|
assert.equal(handle.isReady(), true)
|
|
129
|
-
|
|
130
|
-
assert.equal(v?.foo, "bar")
|
|
126
|
+
assert.equal(v.foo, "bar")
|
|
131
127
|
})
|
|
132
128
|
|
|
133
129
|
it("can clone a document", () => {
|
|
@@ -207,12 +203,11 @@ describe("Repo", () => {
|
|
|
207
203
|
assert.equal(doc, undefined)
|
|
208
204
|
})
|
|
209
205
|
|
|
210
|
-
it("
|
|
206
|
+
it("emits an unavailable event when you don't have the document locally and are not connected to anyone", async () => {
|
|
211
207
|
const { repo } = setup()
|
|
212
208
|
const url = generateAutomergeUrl()
|
|
213
209
|
const handle = repo.find<TestDoc>(url)
|
|
214
210
|
assert.equal(handle.isReady(), false)
|
|
215
|
-
|
|
216
211
|
await eventPromise(handle, "unavailable")
|
|
217
212
|
})
|
|
218
213
|
|
|
@@ -255,7 +250,6 @@ describe("Repo", () => {
|
|
|
255
250
|
|
|
256
251
|
const repo2 = new Repo({
|
|
257
252
|
storage: storageAdapter,
|
|
258
|
-
network: [],
|
|
259
253
|
})
|
|
260
254
|
|
|
261
255
|
const bobHandle = repo2.find<TestDoc>(handle.url)
|
|
@@ -277,7 +271,6 @@ describe("Repo", () => {
|
|
|
277
271
|
|
|
278
272
|
const repo2 = new Repo({
|
|
279
273
|
storage: storageAdapter,
|
|
280
|
-
network: [],
|
|
281
274
|
})
|
|
282
275
|
|
|
283
276
|
const bobHandle = repo2.find<TestDoc>(handle.url)
|
|
@@ -364,7 +357,6 @@ describe("Repo", () => {
|
|
|
364
357
|
|
|
365
358
|
const repo = new Repo({
|
|
366
359
|
storage,
|
|
367
|
-
network: [],
|
|
368
360
|
})
|
|
369
361
|
|
|
370
362
|
const handle = repo.create<{ count: number }>()
|
|
@@ -376,14 +368,12 @@ describe("Repo", () => {
|
|
|
376
368
|
d.count = 1
|
|
377
369
|
})
|
|
378
370
|
|
|
379
|
-
|
|
380
|
-
await pause()
|
|
371
|
+
await repo.flush()
|
|
381
372
|
|
|
382
373
|
const initialKeys = storage.keys()
|
|
383
374
|
|
|
384
375
|
const repo2 = new Repo({
|
|
385
376
|
storage,
|
|
386
|
-
network: [],
|
|
387
377
|
})
|
|
388
378
|
const handle2 = repo2.find(handle.url)
|
|
389
379
|
await handle2.doc()
|
|
@@ -396,7 +386,6 @@ describe("Repo", () => {
|
|
|
396
386
|
|
|
397
387
|
const repo = new Repo({
|
|
398
388
|
storage,
|
|
399
|
-
network: [],
|
|
400
389
|
})
|
|
401
390
|
|
|
402
391
|
const handle = repo.create<{ count: number }>()
|
|
@@ -411,7 +400,6 @@ describe("Repo", () => {
|
|
|
411
400
|
for (let i = 0; i < 3; i++) {
|
|
412
401
|
const repo2 = new Repo({
|
|
413
402
|
storage,
|
|
414
|
-
network: [],
|
|
415
403
|
})
|
|
416
404
|
const handle2 = repo2.find(handle.url)
|
|
417
405
|
await handle2.doc()
|
|
@@ -452,12 +440,159 @@ describe("Repo", () => {
|
|
|
452
440
|
expect(A.getHistory(v)).toEqual(A.getHistory(updatedDoc))
|
|
453
441
|
})
|
|
454
442
|
|
|
455
|
-
it("throws an error if we try to import
|
|
443
|
+
it("throws an error if we try to import a nonsensical byte array", async () => {
|
|
456
444
|
const { repo } = setup()
|
|
457
445
|
expect(() => {
|
|
458
|
-
repo.import<TestDoc>(
|
|
446
|
+
repo.import<TestDoc>(new Uint8Array([1, 2, 3]))
|
|
459
447
|
}).toThrow()
|
|
460
448
|
})
|
|
449
|
+
|
|
450
|
+
// TODO: not sure if this is the desired behavior from `import`.
|
|
451
|
+
|
|
452
|
+
it("makes an empty document if we try to import an automerge doc", async () => {
|
|
453
|
+
const { repo } = setup()
|
|
454
|
+
// @ts-ignore - passing something other than UInt8Array
|
|
455
|
+
const handle = repo.import<TestDoc>(A.from({ foo: 123 }))
|
|
456
|
+
const doc = await handle.doc()
|
|
457
|
+
expect(doc).toEqual({})
|
|
458
|
+
})
|
|
459
|
+
|
|
460
|
+
it("makes an empty document if we try to import a plain object", async () => {
|
|
461
|
+
const { repo } = setup()
|
|
462
|
+
// @ts-ignore - passing something other than UInt8Array
|
|
463
|
+
const handle = repo.import<TestDoc>({ foo: 123 })
|
|
464
|
+
const doc = await handle.doc()
|
|
465
|
+
expect(doc).toEqual({})
|
|
466
|
+
})
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
describe("flush behaviour", () => {
|
|
470
|
+
const setup = () => {
|
|
471
|
+
let blockedSaves = new Set<{ path: StorageKey; resolve: () => void }>()
|
|
472
|
+
let resume = (documentIds?: DocumentId[]) => {
|
|
473
|
+
const savesToUnblock = documentIds
|
|
474
|
+
? Array.from(blockedSaves).filter(({ path }) =>
|
|
475
|
+
documentIds.some(documentId => path.includes(documentId))
|
|
476
|
+
)
|
|
477
|
+
: Array.from(blockedSaves)
|
|
478
|
+
savesToUnblock.forEach(({ resolve }) => resolve())
|
|
479
|
+
}
|
|
480
|
+
const pausedStorage = new DummyStorageAdapter()
|
|
481
|
+
{
|
|
482
|
+
const originalSave = pausedStorage.save.bind(pausedStorage)
|
|
483
|
+
pausedStorage.save = async (...args) => {
|
|
484
|
+
await new Promise<void>(resolve => {
|
|
485
|
+
const blockedSave = {
|
|
486
|
+
path: args[0],
|
|
487
|
+
resolve: () => {
|
|
488
|
+
resolve()
|
|
489
|
+
blockedSaves.delete(blockedSave)
|
|
490
|
+
},
|
|
491
|
+
}
|
|
492
|
+
blockedSaves.add(blockedSave)
|
|
493
|
+
})
|
|
494
|
+
await pause(0)
|
|
495
|
+
// otherwise all the save promises resolve together
|
|
496
|
+
// which prevents testing flushing a single docID
|
|
497
|
+
return originalSave(...args)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const repo = new Repo({
|
|
502
|
+
storage: pausedStorage,
|
|
503
|
+
})
|
|
504
|
+
|
|
505
|
+
// Create a pair of handles
|
|
506
|
+
const handle = repo.create<{ foo: string }>({ foo: "first" })
|
|
507
|
+
const handle2 = repo.create<{ foo: string }>({ foo: "second" })
|
|
508
|
+
return { resume, pausedStorage, repo, handle, handle2 }
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
it("should not be in a new repo yet because the storage is slow", async () => {
|
|
512
|
+
const { pausedStorage, repo, handle, handle2 } = setup()
|
|
513
|
+
expect((await handle.doc()).foo).toEqual("first")
|
|
514
|
+
expect((await handle2.doc()).foo).toEqual("second")
|
|
515
|
+
|
|
516
|
+
// Reload repo
|
|
517
|
+
const repo2 = new Repo({
|
|
518
|
+
storage: pausedStorage,
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
// Could not find the document that is not yet saved because of slow storage.
|
|
522
|
+
const reloadedHandle = repo2.find<{ foo: string }>(handle.url)
|
|
523
|
+
expect(pausedStorage.keys()).to.deep.equal([])
|
|
524
|
+
expect(await reloadedHandle.doc()).toEqual(undefined)
|
|
525
|
+
})
|
|
526
|
+
|
|
527
|
+
it("should be visible to a new repo after flush()", async () => {
|
|
528
|
+
const { resume, pausedStorage, repo, handle, handle2 } = setup()
|
|
529
|
+
|
|
530
|
+
const flushPromise = repo.flush()
|
|
531
|
+
resume()
|
|
532
|
+
await flushPromise
|
|
533
|
+
|
|
534
|
+
// Check that the data is now saved.
|
|
535
|
+
expect(pausedStorage.keys().length).toBeGreaterThan(0)
|
|
536
|
+
|
|
537
|
+
{
|
|
538
|
+
// Reload repo
|
|
539
|
+
const repo = new Repo({
|
|
540
|
+
storage: pausedStorage,
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
expect(
|
|
544
|
+
(await repo.find<{ foo: string }>(handle.documentId).doc()).foo
|
|
545
|
+
).toEqual("first")
|
|
546
|
+
expect(
|
|
547
|
+
(await repo.find<{ foo: string }>(handle2.documentId).doc()).foo
|
|
548
|
+
).toEqual("second")
|
|
549
|
+
}
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
it("should only block on flushing requested documents", async () => {
|
|
553
|
+
const { resume, pausedStorage, repo, handle, handle2 } = setup()
|
|
554
|
+
|
|
555
|
+
const flushPromise = repo.flush([handle.documentId])
|
|
556
|
+
resume([handle.documentId])
|
|
557
|
+
await flushPromise
|
|
558
|
+
|
|
559
|
+
// Check that the data is now saved.
|
|
560
|
+
expect(pausedStorage.keys().length).toBeGreaterThan(0)
|
|
561
|
+
|
|
562
|
+
{
|
|
563
|
+
// Reload repo
|
|
564
|
+
const repo = new Repo({
|
|
565
|
+
storage: pausedStorage,
|
|
566
|
+
})
|
|
567
|
+
|
|
568
|
+
expect(
|
|
569
|
+
(await repo.find<{ foo: string }>(handle.documentId).doc()).foo
|
|
570
|
+
).toEqual("first")
|
|
571
|
+
// Really, it's okay if the second one is also flushed but I'm forcing the issue
|
|
572
|
+
// in the test storage engine above to make sure the behaviour is as documented
|
|
573
|
+
expect(
|
|
574
|
+
await repo.find<{ foo: string }>(handle2.documentId).doc()
|
|
575
|
+
).toEqual(undefined)
|
|
576
|
+
}
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
it("flush right before change should resolve correctly", async () => {
|
|
580
|
+
const repo = new Repo({
|
|
581
|
+
network: [],
|
|
582
|
+
storage: new DummyStorageAdapter(),
|
|
583
|
+
})
|
|
584
|
+
const handle = repo.create<{ field?: string }>()
|
|
585
|
+
|
|
586
|
+
for (let i = 0; i < 10; i++) {
|
|
587
|
+
const flushPromise = repo.flush([handle.documentId])
|
|
588
|
+
handle.change((doc: any) => {
|
|
589
|
+
doc.field += Array(1024)
|
|
590
|
+
.fill(Math.random() * 10)
|
|
591
|
+
.join("")
|
|
592
|
+
})
|
|
593
|
+
await flushPromise
|
|
594
|
+
}
|
|
595
|
+
})
|
|
461
596
|
})
|
|
462
597
|
|
|
463
598
|
describe("with peers (linear network)", async () => {
|
|
@@ -695,9 +830,7 @@ describe("Repo", () => {
|
|
|
695
830
|
it("charlieRepo can request a document not initially shared with it", async () => {
|
|
696
831
|
const { charlieRepo, notForCharlie, teardown } = await setup()
|
|
697
832
|
|
|
698
|
-
const handle = charlieRepo.find<TestDoc>(
|
|
699
|
-
stringifyAutomergeUrl({ documentId: notForCharlie })
|
|
700
|
-
)
|
|
833
|
+
const handle = charlieRepo.find<TestDoc>(notForCharlie)
|
|
701
834
|
|
|
702
835
|
await pause(50)
|
|
703
836
|
|
|
@@ -711,9 +844,7 @@ describe("Repo", () => {
|
|
|
711
844
|
it("charlieRepo can request a document across a network of multiple peers", async () => {
|
|
712
845
|
const { charlieRepo, notForBob, teardown } = await setup()
|
|
713
846
|
|
|
714
|
-
const handle = charlieRepo.find<TestDoc>(
|
|
715
|
-
stringifyAutomergeUrl({ documentId: notForBob })
|
|
716
|
-
)
|
|
847
|
+
const handle = charlieRepo.find<TestDoc>(notForBob)
|
|
717
848
|
|
|
718
849
|
await pause(50)
|
|
719
850
|
|
|
@@ -735,7 +866,16 @@ describe("Repo", () => {
|
|
|
735
866
|
teardown()
|
|
736
867
|
})
|
|
737
868
|
|
|
738
|
-
it("
|
|
869
|
+
it("emits an unavailable event when it's not found on the network", async () => {
|
|
870
|
+
const { aliceRepo, teardown } = await setup()
|
|
871
|
+
const url = generateAutomergeUrl()
|
|
872
|
+
const handle = aliceRepo.find(url)
|
|
873
|
+
assert.equal(handle.isReady(), false)
|
|
874
|
+
await eventPromise(handle, "unavailable")
|
|
875
|
+
teardown()
|
|
876
|
+
})
|
|
877
|
+
|
|
878
|
+
it("emits an unavailable event every time an unavailable doc is requested", async () => {
|
|
739
879
|
const { charlieRepo, teardown } = await setup()
|
|
740
880
|
const url = generateAutomergeUrl()
|
|
741
881
|
const handle = charlieRepo.find<TestDoc>(url)
|
|
@@ -746,10 +886,13 @@ describe("Repo", () => {
|
|
|
746
886
|
eventPromise(charlieRepo, "unavailable-document"),
|
|
747
887
|
])
|
|
748
888
|
|
|
749
|
-
// make sure it
|
|
889
|
+
// make sure it emits a second time if the doc is still unavailable
|
|
750
890
|
const handle2 = charlieRepo.find<TestDoc>(url)
|
|
751
891
|
assert.equal(handle2.isReady(), false)
|
|
752
|
-
await
|
|
892
|
+
await Promise.all([
|
|
893
|
+
eventPromise(handle, "unavailable"),
|
|
894
|
+
eventPromise(charlieRepo, "unavailable-document"),
|
|
895
|
+
])
|
|
753
896
|
|
|
754
897
|
teardown()
|
|
755
898
|
})
|
|
@@ -773,7 +916,7 @@ describe("Repo", () => {
|
|
|
773
916
|
|
|
774
917
|
await eventPromise(aliceRepo.networkSubsystem, "peer")
|
|
775
918
|
|
|
776
|
-
const doc = await handle.doc([
|
|
919
|
+
const doc = await handle.doc(["ready"])
|
|
777
920
|
assert.deepStrictEqual(doc, { foo: "baz" })
|
|
778
921
|
|
|
779
922
|
// an additional find should also return the correct resolved document
|
|
@@ -797,7 +940,6 @@ describe("Repo", () => {
|
|
|
797
940
|
// we have a storage containing the document to pass to a new repo later
|
|
798
941
|
const storage = new DummyStorageAdapter()
|
|
799
942
|
const isolatedRepo = new Repo({
|
|
800
|
-
network: [],
|
|
801
943
|
storage,
|
|
802
944
|
})
|
|
803
945
|
const unsyncedHandle = isolatedRepo.create<TestDoc>()
|
|
@@ -855,17 +997,6 @@ describe("Repo", () => {
|
|
|
855
997
|
teardown()
|
|
856
998
|
})
|
|
857
999
|
|
|
858
|
-
it("can emit an 'unavailable' event when it's not found on the network", async () => {
|
|
859
|
-
const { charlieRepo, teardown } = await setup()
|
|
860
|
-
|
|
861
|
-
const url = generateAutomergeUrl()
|
|
862
|
-
const handle = charlieRepo.find<TestDoc>(url)
|
|
863
|
-
assert.equal(handle.isReady(), false)
|
|
864
|
-
|
|
865
|
-
await eventPromise(handle, "unavailable")
|
|
866
|
-
teardown()
|
|
867
|
-
})
|
|
868
|
-
|
|
869
1000
|
it("syncs a bunch of changes", async () => {
|
|
870
1001
|
const { aliceRepo, bobRepo, charlieRepo, teardown } = await setup()
|
|
871
1002
|
|
|
@@ -949,8 +1080,7 @@ describe("Repo", () => {
|
|
|
949
1080
|
bobHandle.documentId,
|
|
950
1081
|
await charlieRepo!.storageSubsystem.id()
|
|
951
1082
|
)
|
|
952
|
-
|
|
953
|
-
assert.deepStrictEqual(storedSyncState.sharedHeads, docHeads)
|
|
1083
|
+
assert.deepStrictEqual(storedSyncState.sharedHeads, bobHandle.heads())
|
|
954
1084
|
|
|
955
1085
|
teardown()
|
|
956
1086
|
})
|
|
@@ -1003,7 +1133,6 @@ describe("Repo", () => {
|
|
|
1003
1133
|
// setup new repo which uses bob's storage
|
|
1004
1134
|
const bob2Repo = new Repo({
|
|
1005
1135
|
storage: bobStorage,
|
|
1006
|
-
network: [],
|
|
1007
1136
|
peerId: "bob-2" as PeerId,
|
|
1008
1137
|
})
|
|
1009
1138
|
|
|
@@ -1067,18 +1196,15 @@ describe("Repo", () => {
|
|
|
1067
1196
|
// pause to let the sync happen
|
|
1068
1197
|
await pause(100)
|
|
1069
1198
|
|
|
1070
|
-
|
|
1071
|
-
const bobHeads = A.getHeads(handle.docSync())
|
|
1072
|
-
|
|
1073
|
-
assert.deepStrictEqual(charlieHeads, bobHeads)
|
|
1199
|
+
assert.deepStrictEqual(charlieHandle.heads(), handle.heads())
|
|
1074
1200
|
|
|
1075
1201
|
const nextRemoteHeads = await nextRemoteHeadsPromise
|
|
1076
1202
|
assert.deepStrictEqual(nextRemoteHeads.storageId, charliedStorageId)
|
|
1077
|
-
assert.deepStrictEqual(nextRemoteHeads.heads,
|
|
1203
|
+
assert.deepStrictEqual(nextRemoteHeads.heads, charlieHandle.heads())
|
|
1078
1204
|
|
|
1079
1205
|
assert.deepStrictEqual(
|
|
1080
1206
|
handle.getRemoteHeads(charliedStorageId),
|
|
1081
|
-
|
|
1207
|
+
charlieHandle.heads()
|
|
1082
1208
|
)
|
|
1083
1209
|
|
|
1084
1210
|
teardown()
|
|
@@ -1115,14 +1241,14 @@ describe("Repo", () => {
|
|
|
1115
1241
|
|
|
1116
1242
|
const bobDoc = bobRepo.find(aliceDoc.url)
|
|
1117
1243
|
bobDoc.unavailable()
|
|
1118
|
-
await bobDoc
|
|
1244
|
+
await eventPromise(bobDoc, "unavailable")
|
|
1119
1245
|
|
|
1120
1246
|
aliceAdapter.peerCandidate(bob)
|
|
1121
1247
|
// Bob isn't yet connected to Alice and can't respond to her sync message
|
|
1122
1248
|
await pause(100)
|
|
1123
1249
|
bobAdapter.peerCandidate(alice)
|
|
1124
1250
|
|
|
1125
|
-
await bobDoc.whenReady(
|
|
1251
|
+
await bobDoc.whenReady()
|
|
1126
1252
|
|
|
1127
1253
|
assert.equal(bobDoc.isReady(), true)
|
|
1128
1254
|
})
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { pause } from "../../src/helpers/pause.js"
|
|
1
|
+
import { pause } from "../../src/helpers/pause.js"
|
|
2
2
|
import { Message, NetworkAdapter, PeerId } from "../../src/index.js"
|
|
3
3
|
|
|
4
4
|
export class DummyNetworkAdapter extends NetworkAdapter {
|
|
5
5
|
#startReady: boolean
|
|
6
|
-
#sendMessage?: SendMessageFn
|
|
6
|
+
#sendMessage?: SendMessageFn
|
|
7
7
|
|
|
8
|
-
constructor(opts: Options = {startReady: true}) {
|
|
8
|
+
constructor(opts: Options = { startReady: true }) {
|
|
9
9
|
super()
|
|
10
|
-
this.#startReady = opts.startReady
|
|
11
|
-
this.#sendMessage = opts.sendMessage
|
|
10
|
+
this.#startReady = opts.startReady
|
|
11
|
+
this.#sendMessage = opts.sendMessage
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
connect(peerId: PeerId) {
|
|
15
|
-
this.peerId = peerId
|
|
15
|
+
this.peerId = peerId
|
|
16
16
|
if (this.#startReady) {
|
|
17
17
|
this.emit("ready", { network: this })
|
|
18
18
|
}
|
|
@@ -21,34 +21,36 @@ export class DummyNetworkAdapter extends NetworkAdapter {
|
|
|
21
21
|
disconnect() {}
|
|
22
22
|
|
|
23
23
|
peerCandidate(peerId: PeerId) {
|
|
24
|
-
this.emit(
|
|
24
|
+
this.emit("peer-candidate", { peerId, peerMetadata: {} })
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
override send(message: Message) {
|
|
28
|
-
this.#sendMessage?.(message)
|
|
28
|
+
this.#sendMessage?.(message)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
receive(message: Message) {
|
|
32
|
-
this.emit(
|
|
32
|
+
this.emit("message", message)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
static createConnectedPair({ latency = 10 }: { latency?: number} = {}) {
|
|
35
|
+
static createConnectedPair({ latency = 10 }: { latency?: number } = {}) {
|
|
36
36
|
const adapter1: DummyNetworkAdapter = new DummyNetworkAdapter({
|
|
37
37
|
startReady: true,
|
|
38
|
-
sendMessage: (message: Message) =>
|
|
39
|
-
|
|
38
|
+
sendMessage: (message: Message) =>
|
|
39
|
+
pause(latency).then(() => adapter2.receive(message)),
|
|
40
|
+
})
|
|
40
41
|
const adapter2: DummyNetworkAdapter = new DummyNetworkAdapter({
|
|
41
42
|
startReady: true,
|
|
42
|
-
sendMessage: (message: Message) =>
|
|
43
|
-
|
|
43
|
+
sendMessage: (message: Message) =>
|
|
44
|
+
pause(latency).then(() => adapter1.receive(message)),
|
|
45
|
+
})
|
|
44
46
|
|
|
45
|
-
return [adapter1, adapter2]
|
|
47
|
+
return [adapter1, adapter2]
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
type SendMessageFn = (message: Message) => void
|
|
51
|
+
type SendMessageFn = (message: Message) => void
|
|
50
52
|
|
|
51
53
|
type Options = {
|
|
52
|
-
startReady?: boolean
|
|
53
|
-
sendMessage?: SendMessageFn
|
|
54
|
+
startReady?: boolean
|
|
55
|
+
sendMessage?: SendMessageFn
|
|
54
56
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Chunk,
|
|
3
|
+
StorageAdapterInterface,
|
|
4
|
+
type StorageKey,
|
|
5
|
+
} from "../../src/index.js"
|
|
2
6
|
|
|
3
7
|
export class DummyStorageAdapter implements StorageAdapterInterface {
|
|
4
8
|
#data: Record<string, Uint8Array> = {}
|
package/test/remoteHeads.test.ts
CHANGED
|
@@ -152,7 +152,7 @@ describe("DocHandle.remoteHeads", () => {
|
|
|
152
152
|
// wait for alice's service worker to acknowledge the change
|
|
153
153
|
const { heads } = await aliceSeenByBobPromise
|
|
154
154
|
|
|
155
|
-
assert.deepStrictEqual(heads,
|
|
155
|
+
assert.deepStrictEqual(heads, aliceServiceWorkerDoc.heads())
|
|
156
156
|
})
|
|
157
157
|
|
|
158
158
|
it("should report remoteHeads only for documents the subscriber has open", async () => {
|