@automerge/automerge-repo 1.0.0-alpha.3 → 1.0.0-alpha.5

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 (61) hide show
  1. package/dist/DocCollection.d.ts +2 -1
  2. package/dist/DocCollection.d.ts.map +1 -1
  3. package/dist/DocCollection.js +3 -3
  4. package/dist/DocHandle.d.ts +8 -3
  5. package/dist/DocHandle.d.ts.map +1 -1
  6. package/dist/DocHandle.js +28 -6
  7. package/dist/DocUrl.d.ts +1 -1
  8. package/dist/DocUrl.d.ts.map +1 -1
  9. package/dist/Repo.d.ts.map +1 -1
  10. package/dist/Repo.js +25 -7
  11. package/dist/helpers/cbor.d.ts +4 -0
  12. package/dist/helpers/cbor.d.ts.map +1 -0
  13. package/dist/helpers/cbor.js +8 -0
  14. package/dist/helpers/eventPromise.d.ts +1 -1
  15. package/dist/helpers/eventPromise.d.ts.map +1 -1
  16. package/dist/helpers/headsAreSame.d.ts +0 -1
  17. package/dist/helpers/headsAreSame.d.ts.map +1 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/network/NetworkAdapter.d.ts +4 -5
  22. package/dist/network/NetworkAdapter.d.ts.map +1 -1
  23. package/dist/network/NetworkAdapter.js +1 -1
  24. package/dist/network/NetworkSubsystem.d.ts +4 -4
  25. package/dist/network/NetworkSubsystem.d.ts.map +1 -1
  26. package/dist/network/NetworkSubsystem.js +28 -14
  27. package/dist/network/messages.d.ts +2 -2
  28. package/dist/network/messages.d.ts.map +1 -1
  29. package/dist/storage/StorageSubsystem.d.ts +1 -1
  30. package/dist/storage/StorageSubsystem.d.ts.map +1 -1
  31. package/dist/storage/StorageSubsystem.js +10 -4
  32. package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
  33. package/dist/synchronizer/DocSynchronizer.js +11 -12
  34. package/dist/synchronizer/Synchronizer.d.ts +1 -1
  35. package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
  36. package/dist/synchronizer/Synchronizer.js +1 -1
  37. package/fuzz/fuzz.ts +1 -1
  38. package/package.json +3 -3
  39. package/src/DocCollection.ts +4 -3
  40. package/src/DocHandle.ts +34 -4
  41. package/src/DocUrl.ts +1 -1
  42. package/src/Repo.ts +23 -7
  43. package/src/helpers/cbor.ts +10 -0
  44. package/src/helpers/eventPromise.ts +1 -1
  45. package/src/helpers/headsAreSame.ts +1 -1
  46. package/src/index.ts +2 -0
  47. package/src/network/NetworkAdapter.ts +4 -6
  48. package/src/network/NetworkSubsystem.ts +37 -19
  49. package/src/network/messages.ts +2 -2
  50. package/src/storage/StorageSubsystem.ts +11 -4
  51. package/src/synchronizer/DocSynchronizer.ts +14 -14
  52. package/src/synchronizer/Synchronizer.ts +1 -1
  53. package/test/CollectionSynchronizer.test.ts +1 -1
  54. package/test/DocCollection.test.ts +2 -2
  55. package/test/DocHandle.test.ts +5 -5
  56. package/test/Repo.test.ts +75 -13
  57. package/test/StorageSubsystem.test.ts +2 -3
  58. package/test/helpers/DummyNetworkAdapter.ts +13 -5
  59. package/test/helpers/DummyStorageAdapter.ts +1 -1
  60. package/test/helpers/generate-large-object.ts +13 -0
  61. package/tsconfig.json +2 -2
package/test/Repo.test.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  DocumentId,
9
9
  PeerId,
10
10
  SharePolicy,
11
- } from "../src"
11
+ } from "../src/index.js"
12
12
  import { eventPromise } from "../src/helpers/eventPromise.js"
13
13
  import { pause, rejectOnTimeout } from "../src/helpers/pause.js"
14
14
  import { Repo } from "../src/Repo.js"
@@ -16,19 +16,24 @@ import { DummyNetworkAdapter } from "./helpers/DummyNetworkAdapter.js"
16
16
  import { DummyStorageAdapter } from "./helpers/DummyStorageAdapter.js"
17
17
  import { getRandomItem } from "./helpers/getRandomItem.js"
18
18
  import { TestDoc } from "./types.js"
19
- import { generateAutomergeUrl, stringifyAutomergeUrl } from "../src/DocUrl"
20
- import { READY } from "../src/DocHandle"
19
+ import { generateAutomergeUrl, stringifyAutomergeUrl } from "../src/DocUrl.js"
20
+ import { READY, AWAITING_NETWORK } from "../src/DocHandle.js"
21
+ import {
22
+ generateLargeObject,
23
+ LargeObject,
24
+ } from "./helpers/generate-large-object.js"
21
25
 
22
26
  describe("Repo", () => {
23
27
  describe("single repo", () => {
24
- const setup = () => {
28
+ const setup = (networkReady = true) => {
25
29
  const storageAdapter = new DummyStorageAdapter()
30
+ const networkAdapter = new DummyNetworkAdapter(networkReady)
26
31
 
27
32
  const repo = new Repo({
28
33
  storage: storageAdapter,
29
- network: [new DummyNetworkAdapter()],
34
+ network: [networkAdapter],
30
35
  })
31
- return { repo, storageAdapter }
36
+ return { repo, storageAdapter, networkAdapter }
32
37
  }
33
38
 
34
39
  it("can instantiate a Repo", () => {
@@ -83,6 +88,22 @@ describe("Repo", () => {
83
88
  await eventPromise(handle, "unavailable")
84
89
  })
85
90
 
91
+ it("doesn't mark a document as unavailable until network adapters are ready", async () => {
92
+ const { repo, networkAdapter } = setup(false)
93
+ const url = generateAutomergeUrl()
94
+ const handle = repo.find<TestDoc>(url)
95
+
96
+ let wasUnavailable = false
97
+ handle.on("unavailable", () => {
98
+ wasUnavailable = true
99
+ })
100
+ await pause(50)
101
+ assert.equal(wasUnavailable, false)
102
+
103
+ networkAdapter.emit("ready", { network: networkAdapter })
104
+ await eventPromise(handle, "unavailable")
105
+ })
106
+
86
107
  it("can find a created document", async () => {
87
108
  const { repo } = setup()
88
109
  const handle = repo.create<TestDoc>()
@@ -100,6 +121,20 @@ describe("Repo", () => {
100
121
  assert.equal(v?.foo, "bar")
101
122
  })
102
123
 
124
+ it("saves the document when creating it", async () => {
125
+ const { repo, storageAdapter } = setup()
126
+ const handle = repo.create<TestDoc>()
127
+
128
+ const repo2 = new Repo({
129
+ storage: storageAdapter,
130
+ network: [],
131
+ })
132
+
133
+ const bobHandle = repo2.find<TestDoc>(handle.url)
134
+ await bobHandle.whenReady()
135
+ assert.equal(bobHandle.isReady(), true)
136
+ })
137
+
103
138
  it("saves the document when changed and can find it again", async () => {
104
139
  const { repo, storageAdapter } = setup()
105
140
  const handle = repo.create<TestDoc>()
@@ -129,6 +164,7 @@ describe("Repo", () => {
129
164
  handle.change(d => {
130
165
  d.foo = "bar"
131
166
  })
167
+ // we now have a snapshot and an incremental change in storage
132
168
  assert.equal(handle.isReady(), true)
133
169
  await handle.doc()
134
170
  repo.delete(handle.documentId)
@@ -241,6 +277,21 @@ describe("Repo", () => {
241
277
  assert(storage.keys().length !== 0)
242
278
  }
243
279
  })
280
+
281
+ it("doesn't create multiple snapshots in storage when a series of large changes are made in succession", async () => {
282
+ const { repo, storageAdapter } = setup()
283
+ const handle = repo.create<{ objects: LargeObject[] }>()
284
+
285
+ for (let i = 0; i < 5; i++) {
286
+ handle.change(d => {
287
+ d.objects = []
288
+ d.objects.push(generateLargeObject(100))
289
+ })
290
+ }
291
+
292
+ const storageKeyTypes = storageAdapter.keys().map(k => k.split(".")[1])
293
+ assert(storageKeyTypes.filter(k => k === "snapshot").length === 1)
294
+ })
244
295
  })
245
296
 
246
297
  describe("sync", async () => {
@@ -297,17 +348,28 @@ describe("Repo", () => {
297
348
  bobCharlieChannel.port1.close()
298
349
  }
299
350
 
351
+ function doConnectAlice() {
352
+ aliceRepo.networkSubsystem.addNetworkAdapter(
353
+ new MessageChannelNetworkAdapter(aliceToBob)
354
+ )
355
+ //bobRepo.networkSubsystem.addNetworkAdapter(new MessageChannelNetworkAdapter(bobToAlice))
356
+ }
357
+
358
+ if (connectAlice) {
359
+ doConnectAlice()
360
+ }
361
+
300
362
  return {
301
363
  teardown,
302
364
  aliceRepo,
303
365
  bobRepo,
304
366
  charlieRepo,
305
- aliceNetworkAdapter,
367
+ connectAliceToBob: doConnectAlice,
306
368
  }
307
369
  }
308
370
 
309
371
  const setup = async (connectAlice = true) => {
310
- const { teardown, aliceRepo, bobRepo, charlieRepo, aliceNetworkAdapter } =
372
+ const { teardown, aliceRepo, bobRepo, charlieRepo, connectAliceToBob } =
311
373
  setupRepos(connectAlice)
312
374
 
313
375
  const aliceHandle = aliceRepo.create<TestDoc>()
@@ -345,7 +407,7 @@ describe("Repo", () => {
345
407
  notForCharlie,
346
408
  notForBob,
347
409
  teardown,
348
- aliceNetworkAdapter,
410
+ connectAliceToBob,
349
411
  }
350
412
  }
351
413
 
@@ -443,7 +505,7 @@ describe("Repo", () => {
443
505
  notForCharlie,
444
506
  aliceRepo,
445
507
  teardown,
446
- aliceNetworkAdapter,
508
+ connectAliceToBob,
447
509
  } = await setup(false)
448
510
 
449
511
  const url = stringifyAutomergeUrl({ documentId: notForCharlie })
@@ -452,7 +514,7 @@ describe("Repo", () => {
452
514
 
453
515
  await eventPromise(handle, "unavailable")
454
516
 
455
- aliceRepo.networkSubsystem.addNetworkAdapter(aliceNetworkAdapter)
517
+ connectAliceToBob()
456
518
 
457
519
  await eventPromise(aliceRepo.networkSubsystem, "peer")
458
520
 
@@ -538,9 +600,9 @@ describe("Repo", () => {
538
600
  const doc =
539
601
  Math.random() < 0.5
540
602
  ? // heads, create a new doc
541
- repo.create<TestDoc>()
603
+ repo.create<TestDoc>()
542
604
  : // tails, pick a random doc
543
- (getRandomItem(docs) as DocHandle<TestDoc>)
605
+ (getRandomItem(docs) as DocHandle<TestDoc>)
544
606
 
545
607
  // make sure the doc is ready
546
608
  if (!doc.isReady()) {
@@ -4,13 +4,12 @@ import path from "path"
4
4
 
5
5
  import assert from "assert"
6
6
 
7
- import A from "@automerge/automerge"
7
+ import * as A from "@automerge/automerge/next"
8
8
 
9
9
  import { DummyStorageAdapter } from "./helpers/DummyStorageAdapter.js"
10
10
  import { NodeFSStorageAdapter } from "@automerge/automerge-repo-storage-nodefs"
11
11
 
12
- import { StorageSubsystem } from "../src"
13
- import { TestDoc } from "./types.js"
12
+ import { StorageSubsystem } from "../src/index.js"
14
13
  import { generateAutomergeUrl, parseAutomergeUrl } from "../src/DocUrl.js"
15
14
 
16
15
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "automerge-repo-tests"))
@@ -1,8 +1,16 @@
1
- import { NetworkAdapter } from "../../src"
1
+ import { NetworkAdapter } from "../../src/index.js"
2
2
 
3
3
  export class DummyNetworkAdapter extends NetworkAdapter {
4
- send() {}
5
- connect(_: string) {}
6
- join() {}
7
- leave() {}
4
+ #startReady = true
5
+ constructor(startReady: boolean) {
6
+ super()
7
+ this.#startReady = startReady
8
+ }
9
+ send() { }
10
+ connect(_: string) {
11
+ if (this.#startReady) {
12
+ this.emit("ready", { network: this })
13
+ }
14
+ }
15
+ disconnect() { }
8
16
  }
@@ -1,4 +1,4 @@
1
- import { StorageAdapter, type StorageKey } from "../../src"
1
+ import { StorageAdapter, type StorageKey } from "../../src/index.js"
2
2
 
3
3
  export class DummyStorageAdapter implements StorageAdapter {
4
4
  #data: Record<string, Uint8Array> = {}
@@ -0,0 +1,13 @@
1
+ export type LargeObject = { [key: string]: number }
2
+
3
+ export function generateLargeObject(size: number): LargeObject {
4
+ const largeObject: LargeObject = {}
5
+
6
+ for (let i = 0; i < size; i++) {
7
+ const key = `key${i}`
8
+ const value = Math.random()
9
+ largeObject[key] = value
10
+ }
11
+
12
+ return largeObject
13
+ }
package/tsconfig.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "compilerOptions": {
3
3
  "target": "ESNext",
4
4
  "jsx": "react",
5
- "module": "ESNext",
6
- "moduleResolution": "node",
5
+ "module": "NodeNext",
6
+ "moduleResolution": "Node16",
7
7
  "declaration": true,
8
8
  "declarationMap": true,
9
9
  "outDir": "./dist",