@automerge/automerge-repo 2.0.0-collectionsync-alpha.1 → 2.0.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 (203) hide show
  1. package/README.md +8 -8
  2. package/dist/AutomergeUrl.d.ts +17 -5
  3. package/dist/AutomergeUrl.d.ts.map +1 -1
  4. package/dist/AutomergeUrl.js +71 -24
  5. package/dist/DocHandle.d.ts +33 -41
  6. package/dist/DocHandle.d.ts.map +1 -1
  7. package/dist/DocHandle.js +105 -66
  8. package/dist/FindProgress.d.ts +30 -0
  9. package/dist/FindProgress.d.ts.map +1 -0
  10. package/dist/FindProgress.js +1 -0
  11. package/dist/RemoteHeadsSubscriptions.d.ts +4 -5
  12. package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -1
  13. package/dist/RemoteHeadsSubscriptions.js +4 -1
  14. package/dist/Repo.d.ts +24 -5
  15. package/dist/Repo.d.ts.map +1 -1
  16. package/dist/Repo.js +355 -169
  17. package/dist/helpers/abortable.d.ts +36 -0
  18. package/dist/helpers/abortable.d.ts.map +1 -0
  19. package/dist/helpers/abortable.js +47 -0
  20. package/dist/helpers/arraysAreEqual.d.ts.map +1 -1
  21. package/dist/helpers/bufferFromHex.d.ts +3 -0
  22. package/dist/helpers/bufferFromHex.d.ts.map +1 -0
  23. package/dist/helpers/bufferFromHex.js +13 -0
  24. package/dist/helpers/debounce.d.ts.map +1 -1
  25. package/dist/helpers/eventPromise.d.ts.map +1 -1
  26. package/dist/helpers/headsAreSame.d.ts +2 -2
  27. package/dist/helpers/headsAreSame.d.ts.map +1 -1
  28. package/dist/helpers/mergeArrays.d.ts +1 -1
  29. package/dist/helpers/mergeArrays.d.ts.map +1 -1
  30. package/dist/helpers/pause.d.ts.map +1 -1
  31. package/dist/helpers/tests/network-adapter-tests.d.ts.map +1 -1
  32. package/dist/helpers/tests/network-adapter-tests.js +13 -13
  33. package/dist/helpers/tests/storage-adapter-tests.d.ts.map +1 -1
  34. package/dist/helpers/tests/storage-adapter-tests.js +6 -9
  35. package/dist/helpers/throttle.d.ts.map +1 -1
  36. package/dist/helpers/withTimeout.d.ts.map +1 -1
  37. package/dist/index.d.ts +35 -7
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +37 -6
  40. package/dist/network/NetworkSubsystem.d.ts +0 -1
  41. package/dist/network/NetworkSubsystem.d.ts.map +1 -1
  42. package/dist/network/NetworkSubsystem.js +0 -3
  43. package/dist/network/messages.d.ts +1 -7
  44. package/dist/network/messages.d.ts.map +1 -1
  45. package/dist/network/messages.js +1 -2
  46. package/dist/storage/StorageAdapter.d.ts +0 -9
  47. package/dist/storage/StorageAdapter.d.ts.map +1 -1
  48. package/dist/storage/StorageAdapter.js +0 -33
  49. package/dist/storage/StorageSubsystem.d.ts +6 -2
  50. package/dist/storage/StorageSubsystem.d.ts.map +1 -1
  51. package/dist/storage/StorageSubsystem.js +131 -37
  52. package/dist/storage/keyHash.d.ts +1 -1
  53. package/dist/storage/keyHash.d.ts.map +1 -1
  54. package/dist/synchronizer/CollectionSynchronizer.d.ts +3 -4
  55. package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
  56. package/dist/synchronizer/CollectionSynchronizer.js +32 -26
  57. package/dist/synchronizer/DocSynchronizer.d.ts +8 -8
  58. package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
  59. package/dist/synchronizer/DocSynchronizer.js +205 -79
  60. package/dist/types.d.ts +4 -1
  61. package/dist/types.d.ts.map +1 -1
  62. package/fuzz/fuzz.ts +3 -3
  63. package/package.json +4 -5
  64. package/src/AutomergeUrl.ts +101 -26
  65. package/src/DocHandle.ts +158 -77
  66. package/src/FindProgress.ts +48 -0
  67. package/src/RemoteHeadsSubscriptions.ts +11 -9
  68. package/src/Repo.ts +465 -180
  69. package/src/helpers/abortable.ts +62 -0
  70. package/src/helpers/bufferFromHex.ts +14 -0
  71. package/src/helpers/headsAreSame.ts +2 -2
  72. package/src/helpers/tests/network-adapter-tests.ts +14 -13
  73. package/src/helpers/tests/storage-adapter-tests.ts +13 -24
  74. package/src/index.ts +57 -38
  75. package/src/network/NetworkSubsystem.ts +0 -4
  76. package/src/network/messages.ts +2 -11
  77. package/src/storage/StorageAdapter.ts +0 -42
  78. package/src/storage/StorageSubsystem.ts +155 -45
  79. package/src/storage/keyHash.ts +1 -1
  80. package/src/synchronizer/CollectionSynchronizer.ts +42 -29
  81. package/src/synchronizer/DocSynchronizer.ts +263 -89
  82. package/src/types.ts +4 -1
  83. package/test/AutomergeUrl.test.ts +130 -0
  84. package/test/CollectionSynchronizer.test.ts +6 -8
  85. package/test/DocHandle.test.ts +161 -77
  86. package/test/DocSynchronizer.test.ts +11 -9
  87. package/test/RemoteHeadsSubscriptions.test.ts +1 -1
  88. package/test/Repo.test.ts +406 -341
  89. package/test/StorageSubsystem.test.ts +95 -20
  90. package/test/remoteHeads.test.ts +28 -13
  91. package/dist/CollectionHandle.d.ts +0 -14
  92. package/dist/CollectionHandle.d.ts.map +0 -1
  93. package/dist/CollectionHandle.js +0 -37
  94. package/dist/DocUrl.d.ts +0 -47
  95. package/dist/DocUrl.d.ts.map +0 -1
  96. package/dist/DocUrl.js +0 -72
  97. package/dist/EphemeralData.d.ts +0 -20
  98. package/dist/EphemeralData.d.ts.map +0 -1
  99. package/dist/EphemeralData.js +0 -1
  100. package/dist/ferigan.d.ts +0 -51
  101. package/dist/ferigan.d.ts.map +0 -1
  102. package/dist/ferigan.js +0 -98
  103. package/dist/src/DocHandle.d.ts +0 -182
  104. package/dist/src/DocHandle.d.ts.map +0 -1
  105. package/dist/src/DocHandle.js +0 -405
  106. package/dist/src/DocUrl.d.ts +0 -49
  107. package/dist/src/DocUrl.d.ts.map +0 -1
  108. package/dist/src/DocUrl.js +0 -72
  109. package/dist/src/EphemeralData.d.ts +0 -19
  110. package/dist/src/EphemeralData.d.ts.map +0 -1
  111. package/dist/src/EphemeralData.js +0 -1
  112. package/dist/src/Repo.d.ts +0 -74
  113. package/dist/src/Repo.d.ts.map +0 -1
  114. package/dist/src/Repo.js +0 -208
  115. package/dist/src/helpers/arraysAreEqual.d.ts +0 -2
  116. package/dist/src/helpers/arraysAreEqual.d.ts.map +0 -1
  117. package/dist/src/helpers/arraysAreEqual.js +0 -2
  118. package/dist/src/helpers/cbor.d.ts +0 -4
  119. package/dist/src/helpers/cbor.d.ts.map +0 -1
  120. package/dist/src/helpers/cbor.js +0 -8
  121. package/dist/src/helpers/eventPromise.d.ts +0 -11
  122. package/dist/src/helpers/eventPromise.d.ts.map +0 -1
  123. package/dist/src/helpers/eventPromise.js +0 -7
  124. package/dist/src/helpers/headsAreSame.d.ts +0 -2
  125. package/dist/src/helpers/headsAreSame.d.ts.map +0 -1
  126. package/dist/src/helpers/headsAreSame.js +0 -4
  127. package/dist/src/helpers/mergeArrays.d.ts +0 -2
  128. package/dist/src/helpers/mergeArrays.d.ts.map +0 -1
  129. package/dist/src/helpers/mergeArrays.js +0 -15
  130. package/dist/src/helpers/pause.d.ts +0 -6
  131. package/dist/src/helpers/pause.d.ts.map +0 -1
  132. package/dist/src/helpers/pause.js +0 -10
  133. package/dist/src/helpers/tests/network-adapter-tests.d.ts +0 -21
  134. package/dist/src/helpers/tests/network-adapter-tests.d.ts.map +0 -1
  135. package/dist/src/helpers/tests/network-adapter-tests.js +0 -122
  136. package/dist/src/helpers/withTimeout.d.ts +0 -12
  137. package/dist/src/helpers/withTimeout.d.ts.map +0 -1
  138. package/dist/src/helpers/withTimeout.js +0 -24
  139. package/dist/src/index.d.ts +0 -53
  140. package/dist/src/index.d.ts.map +0 -1
  141. package/dist/src/index.js +0 -40
  142. package/dist/src/network/NetworkAdapter.d.ts +0 -26
  143. package/dist/src/network/NetworkAdapter.d.ts.map +0 -1
  144. package/dist/src/network/NetworkAdapter.js +0 -4
  145. package/dist/src/network/NetworkSubsystem.d.ts +0 -23
  146. package/dist/src/network/NetworkSubsystem.d.ts.map +0 -1
  147. package/dist/src/network/NetworkSubsystem.js +0 -120
  148. package/dist/src/network/messages.d.ts +0 -85
  149. package/dist/src/network/messages.d.ts.map +0 -1
  150. package/dist/src/network/messages.js +0 -23
  151. package/dist/src/storage/StorageAdapter.d.ts +0 -14
  152. package/dist/src/storage/StorageAdapter.d.ts.map +0 -1
  153. package/dist/src/storage/StorageAdapter.js +0 -1
  154. package/dist/src/storage/StorageSubsystem.d.ts +0 -12
  155. package/dist/src/storage/StorageSubsystem.d.ts.map +0 -1
  156. package/dist/src/storage/StorageSubsystem.js +0 -145
  157. package/dist/src/synchronizer/CollectionSynchronizer.d.ts +0 -25
  158. package/dist/src/synchronizer/CollectionSynchronizer.d.ts.map +0 -1
  159. package/dist/src/synchronizer/CollectionSynchronizer.js +0 -106
  160. package/dist/src/synchronizer/DocSynchronizer.d.ts +0 -29
  161. package/dist/src/synchronizer/DocSynchronizer.d.ts.map +0 -1
  162. package/dist/src/synchronizer/DocSynchronizer.js +0 -263
  163. package/dist/src/synchronizer/Synchronizer.d.ts +0 -9
  164. package/dist/src/synchronizer/Synchronizer.d.ts.map +0 -1
  165. package/dist/src/synchronizer/Synchronizer.js +0 -2
  166. package/dist/src/types.d.ts +0 -16
  167. package/dist/src/types.d.ts.map +0 -1
  168. package/dist/src/types.js +0 -1
  169. package/dist/test/CollectionSynchronizer.test.d.ts +0 -2
  170. package/dist/test/CollectionSynchronizer.test.d.ts.map +0 -1
  171. package/dist/test/CollectionSynchronizer.test.js +0 -57
  172. package/dist/test/DocHandle.test.d.ts +0 -2
  173. package/dist/test/DocHandle.test.d.ts.map +0 -1
  174. package/dist/test/DocHandle.test.js +0 -238
  175. package/dist/test/DocSynchronizer.test.d.ts +0 -2
  176. package/dist/test/DocSynchronizer.test.d.ts.map +0 -1
  177. package/dist/test/DocSynchronizer.test.js +0 -111
  178. package/dist/test/Network.test.d.ts +0 -2
  179. package/dist/test/Network.test.d.ts.map +0 -1
  180. package/dist/test/Network.test.js +0 -11
  181. package/dist/test/Repo.test.d.ts +0 -2
  182. package/dist/test/Repo.test.d.ts.map +0 -1
  183. package/dist/test/Repo.test.js +0 -568
  184. package/dist/test/StorageSubsystem.test.d.ts +0 -2
  185. package/dist/test/StorageSubsystem.test.d.ts.map +0 -1
  186. package/dist/test/StorageSubsystem.test.js +0 -56
  187. package/dist/test/helpers/DummyNetworkAdapter.d.ts +0 -9
  188. package/dist/test/helpers/DummyNetworkAdapter.d.ts.map +0 -1
  189. package/dist/test/helpers/DummyNetworkAdapter.js +0 -15
  190. package/dist/test/helpers/DummyStorageAdapter.d.ts +0 -16
  191. package/dist/test/helpers/DummyStorageAdapter.d.ts.map +0 -1
  192. package/dist/test/helpers/DummyStorageAdapter.js +0 -33
  193. package/dist/test/helpers/generate-large-object.d.ts +0 -5
  194. package/dist/test/helpers/generate-large-object.d.ts.map +0 -1
  195. package/dist/test/helpers/generate-large-object.js +0 -9
  196. package/dist/test/helpers/getRandomItem.d.ts +0 -2
  197. package/dist/test/helpers/getRandomItem.d.ts.map +0 -1
  198. package/dist/test/helpers/getRandomItem.js +0 -4
  199. package/dist/test/types.d.ts +0 -4
  200. package/dist/test/types.d.ts.map +0 -1
  201. package/dist/test/types.js +0 -1
  202. package/src/CollectionHandle.ts +0 -54
  203. package/src/ferigan.ts +0 -184
@@ -4,13 +4,15 @@ import assert from "assert"
4
4
  import fs from "fs"
5
5
  import os from "os"
6
6
  import path from "path"
7
- import { describe, it } from "vitest"
7
+ import { describe, it, expect } from "vitest"
8
8
  import { generateAutomergeUrl, parseAutomergeUrl } from "../src/AutomergeUrl.js"
9
9
  import { PeerId, cbor } from "../src/index.js"
10
10
  import { StorageSubsystem } from "../src/storage/StorageSubsystem.js"
11
11
  import { StorageId } from "../src/storage/types.js"
12
12
  import { DummyStorageAdapter } from "../src/helpers/DummyStorageAdapter.js"
13
13
  import * as Uuid from "uuid"
14
+ import { chunkTypeFromKey } from "../src/storage/chunkTypeFromKey.js"
15
+ import { DocumentId } from "../src/types.js"
14
16
 
15
17
  const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "automerge-repo-tests"))
16
18
 
@@ -21,14 +23,10 @@ describe("StorageSubsystem", () => {
21
23
  }
22
24
 
23
25
  for (const [adapterName, adapter] of Object.entries(adaptersToTest)) {
24
- const beelay = new A.beelay.Beelay({
25
- peerId: "somepeer",
26
- storage: adapter,
27
- })
28
26
  describe(adapterName, () => {
29
27
  describe("Automerge document storage", () => {
30
28
  it("stores and retrieves an Automerge document", async () => {
31
- const storage = new StorageSubsystem(beelay, adapter)
29
+ const storage = new StorageSubsystem(adapter)
32
30
 
33
31
  const doc = A.change(A.init<any>(), "test", d => {
34
32
  d.foo = "bar"
@@ -46,7 +44,7 @@ describe("StorageSubsystem", () => {
46
44
  })
47
45
 
48
46
  it("retrieves an Automerge document following lots of changes", async () => {
49
- const storage = new StorageSubsystem(beelay, adapter)
47
+ const storage = new StorageSubsystem(adapter)
50
48
 
51
49
  type TestDoc = { foo: number }
52
50
 
@@ -64,7 +62,7 @@ describe("StorageSubsystem", () => {
64
62
  }
65
63
 
66
64
  // reload it from storage, simulating a new process
67
- const storage2 = new StorageSubsystem(beelay, adapter)
65
+ const storage2 = new StorageSubsystem(adapter)
68
66
  const reloadedDoc = await storage2.loadDoc<TestDoc>(key)
69
67
 
70
68
  // check that the doc has the right value
@@ -72,7 +70,7 @@ describe("StorageSubsystem", () => {
72
70
  })
73
71
 
74
72
  it("stores incremental changes following a load", async () => {
75
- const storage = new StorageSubsystem(beelay, adapter)
73
+ const storage = new StorageSubsystem(adapter)
76
74
 
77
75
  const doc = A.change(A.init<any>(), "test", d => {
78
76
  d.foo = "bar"
@@ -80,10 +78,10 @@ describe("StorageSubsystem", () => {
80
78
 
81
79
  // save it to storage
82
80
  const key = parseAutomergeUrl(generateAutomergeUrl()).documentId
83
- await storage.saveDoc(key, doc)
81
+ storage.saveDoc(key, doc)
84
82
 
85
83
  // reload it from storage, simulating a new process
86
- const storage2 = new StorageSubsystem(beelay, adapter)
84
+ const storage2 = new StorageSubsystem(adapter)
87
85
  const reloadedDoc = await storage2.loadDoc(key)
88
86
 
89
87
  assert(reloadedDoc, "doc should be loaded")
@@ -97,8 +95,8 @@ describe("StorageSubsystem", () => {
97
95
  storage2.saveDoc(key, changedDoc)
98
96
  })
99
97
 
100
- it.skip("removes an Automerge document", async () => {
101
- const storage = new StorageSubsystem(beelay, adapter)
98
+ it("removes an Automerge document", async () => {
99
+ const storage = new StorageSubsystem(adapter)
102
100
 
103
101
  const doc = A.change(A.init<any>(), "test", d => {
104
102
  d.foo = "bar"
@@ -127,7 +125,7 @@ describe("StorageSubsystem", () => {
127
125
 
128
126
  describe("Arbitrary key/value storage", () => {
129
127
  it("stores and retrieves a blob", async () => {
130
- const storage = new StorageSubsystem(beelay, adapter)
128
+ const storage = new StorageSubsystem(adapter)
131
129
 
132
130
  const value = cbor.encode({ foo: "bar" })
133
131
 
@@ -141,7 +139,7 @@ describe("StorageSubsystem", () => {
141
139
  })
142
140
 
143
141
  it("keeps namespaces separate", async () => {
144
- const storage = new StorageSubsystem(beelay, adapter)
142
+ const storage = new StorageSubsystem(adapter)
145
143
 
146
144
  const key = "ABC123"
147
145
 
@@ -163,7 +161,7 @@ describe("StorageSubsystem", () => {
163
161
  })
164
162
 
165
163
  it("removes a blob", async () => {
166
- const storage = new StorageSubsystem(beelay, adapter)
164
+ const storage = new StorageSubsystem(adapter)
167
165
 
168
166
  const value = cbor.encode({ foo: "bar" })
169
167
 
@@ -184,7 +182,7 @@ describe("StorageSubsystem", () => {
184
182
 
185
183
  describe("sync state", () => {
186
184
  it("stores and retrieve sync state", async () => {
187
- const storage = new StorageSubsystem(beelay, adapter)
185
+ const storage = new StorageSubsystem(adapter)
188
186
 
189
187
  const { documentId } = parseAutomergeUrl(generateAutomergeUrl())
190
188
  const syncState = A.initSyncState()
@@ -201,7 +199,7 @@ describe("StorageSubsystem", () => {
201
199
  })
202
200
 
203
201
  it("delete sync state if document is deleted", async () => {
204
- const storage = new StorageSubsystem(beelay, adapter)
202
+ const storage = new StorageSubsystem(adapter)
205
203
 
206
204
  const { documentId } = parseAutomergeUrl(generateAutomergeUrl())
207
205
  const syncState = A.initSyncState()
@@ -217,7 +215,7 @@ describe("StorageSubsystem", () => {
217
215
  })
218
216
 
219
217
  it("returns a undefined if loading an existing sync state fails", async () => {
220
- const storage = new StorageSubsystem(beelay, adapter)
218
+ const storage = new StorageSubsystem(adapter)
221
219
 
222
220
  const { documentId } = parseAutomergeUrl(generateAutomergeUrl())
223
221
  const bobStorageId = Uuid.v4() as StorageId
@@ -236,7 +234,7 @@ describe("StorageSubsystem", () => {
236
234
 
237
235
  describe("storage id", () => {
238
236
  it("generates a unique id", async () => {
239
- const storage = new StorageSubsystem(beelay, adapter)
237
+ const storage = new StorageSubsystem(adapter)
240
238
 
241
239
  // generate unique id and return same id on subsequence calls
242
240
  const id1 = await storage.id()
@@ -247,6 +245,83 @@ describe("StorageSubsystem", () => {
247
245
  assert.strictEqual(id1, id2)
248
246
  })
249
247
  })
248
+
249
+ describe("loadDoc", () => {
250
+ it("maintains correct document state when loading chunks in order", async () => {
251
+ const storageAdapter = new DummyStorageAdapter()
252
+ const storage = new StorageSubsystem(storageAdapter)
253
+
254
+ // Create a document with multiple changes
255
+ const doc = A.init<{ foo: string }>()
256
+ const doc1 = A.change(doc, d => {
257
+ d.foo = "first"
258
+ })
259
+ const doc2 = A.change(doc1, d => {
260
+ d.foo = "second"
261
+ })
262
+ const doc3 = A.change(doc2, d => {
263
+ d.foo = "third"
264
+ })
265
+
266
+ // Save the document with multiple changes
267
+ const documentId = "test-doc" as DocumentId
268
+ await storage.saveDoc(documentId, doc3)
269
+
270
+ // Load the document
271
+ const loadedDoc = await storage.loadDoc<{ foo: string }>(documentId)
272
+
273
+ // Verify the document state is correct
274
+ expect(loadedDoc?.foo).toBe("third")
275
+ })
276
+
277
+ it("combines chunks with snapshot first", async () => {
278
+ const storageAdapter = new DummyStorageAdapter()
279
+ const storage = new StorageSubsystem(storageAdapter)
280
+
281
+ // Create a document with multiple changes
282
+ const doc = A.init<{ foo: string }>()
283
+ const doc1 = A.change(doc, d => {
284
+ d.foo = "first"
285
+ })
286
+ const doc2 = A.change(doc1, d => {
287
+ d.foo = Array(10000)
288
+ .fill(0)
289
+ .map(() =>
290
+ String.fromCharCode(Math.floor(Math.random() * 26) + 97)
291
+ )
292
+ .join("")
293
+ })
294
+
295
+ // Save the document with multiple changes
296
+ const documentId = "test-doc" as DocumentId
297
+ await storage.saveDoc(documentId, doc2)
298
+
299
+ const doc3 = A.change(doc2, d => {
300
+ d.foo = "third"
301
+ })
302
+ await storage.saveDoc(documentId, doc3)
303
+
304
+ // Load the document
305
+ const loadedDoc = await storage.loadDoc<{ foo: string }>(documentId)
306
+
307
+ // Verify the document state is correct
308
+ expect(loadedDoc?.foo).toBe(doc3.foo)
309
+
310
+ // Get the raw binary data from storage
311
+ const binary = await storage.loadDocData(documentId)
312
+ expect(binary).not.toBeNull()
313
+ if (!binary) return
314
+
315
+ // Verify the binary starts with the Automerge magic value
316
+ expect(binary[0]).toBe(0x85)
317
+ expect(binary[1]).toBe(0x6f)
318
+ expect(binary[2]).toBe(0x4a)
319
+ expect(binary[3]).toBe(0x83)
320
+
321
+ // Verify the chunk type is CHUNK_TYPE_DOCUMENT (0x00)
322
+ expect(binary[8]).toBe(0x00)
323
+ })
324
+ })
250
325
  })
251
326
  }
252
327
  })
@@ -13,8 +13,9 @@ import {
13
13
  import { DummyStorageAdapter } from "../src/helpers/DummyStorageAdapter.js"
14
14
  import { collectMessages } from "./helpers/collectMessages.js"
15
15
  import { TestDoc } from "./types.js"
16
+ import { pause } from "../src/helpers/pause.js"
16
17
 
17
- describe.skip("DocHandle.remoteHeads", () => {
18
+ describe("DocHandle.remoteHeads", () => {
18
19
  const TEST_ID = parseAutomergeUrl(generateAutomergeUrl()).documentId
19
20
 
20
21
  it("should allow to listen for remote head changes and manually read remote heads", async () => {
@@ -128,13 +129,15 @@ describe.skip("DocHandle.remoteHeads", () => {
128
129
  const aliceDoc = alice.create<TestDoc>()
129
130
  aliceDoc.change(d => (d.foo = "bar"))
130
131
 
132
+ await pause(50)
133
+
131
134
  // bob waits for the document to arrive
132
- const bobDoc = bob.find<TestDoc>(aliceDoc.url)
133
- await bobDoc.whenReady()
135
+ const bobDoc = await bob.find<TestDoc>(aliceDoc.url)
134
136
 
135
137
  // alice's service worker waits for the document to arrive
136
- const aliceServiceWorkerDoc = aliceServiceWorker.find(aliceDoc.documentId)
137
- await aliceServiceWorkerDoc.whenReady()
138
+ const aliceServiceWorkerDoc = await aliceServiceWorker.find(
139
+ aliceDoc.documentId
140
+ )
138
141
 
139
142
  let aliceSeenByBobPromise = new Promise<DocHandleRemoteHeadsPayload>(
140
143
  resolve => {
@@ -168,17 +171,21 @@ describe.skip("DocHandle.remoteHeads", () => {
168
171
  const bobDocB = bob.create<TestDoc>()
169
172
  bobDocB.change(d => (d.foo = "B"))
170
173
 
174
+ await pause(50)
175
+
171
176
  // alice opens doc A
172
- const aliceDocA = alice.find<TestDoc>(bobDocA.url)
177
+ const aliceDocAPromise = alice.find<TestDoc>(bobDocA.url)
173
178
 
174
179
  const remoteHeadsChangedMessages = (
175
180
  await collectMessages({
176
181
  emitter: alice.networkSubsystem,
177
182
  event: "message",
178
- until: aliceDocA.whenReady(),
183
+ until: aliceDocAPromise,
179
184
  })
180
185
  ).filter(({ type }) => type === "remote-heads-changed")
181
186
 
187
+ const aliceDocA = await aliceDocAPromise
188
+
182
189
  // we should only be notified of the head changes of doc A
183
190
  assert(
184
191
  remoteHeadsChangedMessages.every(
@@ -197,6 +204,8 @@ describe.skip("DocHandle.remoteHeads", () => {
197
204
  const bobDocB = bob.create<TestDoc>()
198
205
  bobDocB.change(d => (d.foo = "B"))
199
206
 
207
+ await pause(50)
208
+
200
209
  // alice opens the docs
201
210
  const _aliceDocA = alice.find<TestDoc>(bobDocA.url)
202
211
  const _aliceDocB = alice.find<TestDoc>(bobDocB.url)
@@ -209,19 +218,21 @@ describe.skip("DocHandle.remoteHeads", () => {
209
218
  // stored remote heads immediately.
210
219
 
211
220
  // open doc and subscribe alice's second tab to bob's service worker
212
- const alice2DocA = alice2.find<TestDoc>(bobDocA.url)
221
+ const alice2DocAPromise = alice2.find<TestDoc>(bobDocA.url)
213
222
  alice2.subscribeToRemotes([bobServiceWorkerStorageId])
214
223
 
215
224
  const remoteHeadsChangedMessages = (
216
225
  await collectMessages({
217
226
  emitter: alice2.networkSubsystem,
218
227
  event: "message",
219
- until: alice2DocA.whenReady(),
228
+ until: alice2DocAPromise,
220
229
  })
221
230
  ).filter(({ type }) => type === "remote-heads-changed")
222
231
 
232
+ const alice2DocA = await alice2DocAPromise
233
+
223
234
  // we should only be notified of the head changes of doc A
224
- assert.strictEqual(remoteHeadsChangedMessages.length, 2)
235
+ assert.strictEqual(remoteHeadsChangedMessages.length, 1)
225
236
  assert(
226
237
  remoteHeadsChangedMessages.every(
227
238
  d => d.documentId === alice2DocA.documentId
@@ -242,18 +253,22 @@ describe.skip("DocHandle.remoteHeads", () => {
242
253
  // alice subscribes to bob's service worker
243
254
  alice.subscribeToRemotes([bobServiceWorkerStorageId])
244
255
 
256
+ await pause(50)
257
+
245
258
  // alice opens doc A
246
- const alice1DocA = alice.find<TestDoc>(bobDocA.url)
259
+ const alice1DocAPromise = alice.find<TestDoc>(bobDocA.url)
247
260
 
248
261
  const remoteHeadsChangedMessages = (
249
262
  await collectMessages({
250
263
  emitter: alice.networkSubsystem,
251
264
  event: "message",
252
- until: alice1DocA.whenReady(),
265
+ until: alice1DocAPromise,
253
266
  })
254
267
  ).filter(({ type }) => type === "remote-heads-changed")
255
268
 
256
- assert.strictEqual(remoteHeadsChangedMessages.length, 2)
269
+ const alice1DocA = await alice1DocAPromise
270
+
271
+ assert.strictEqual(remoteHeadsChangedMessages.length, 1)
257
272
  assert(
258
273
  remoteHeadsChangedMessages.every(
259
274
  d => d.documentId === alice1DocA.documentId
@@ -1,14 +0,0 @@
1
- import { EventEmitter } from "eventemitter3";
2
- import { Index } from "./ferigan.js";
3
- import { AutomergeUrl } from "./types.js";
4
- import { next as A } from "@automerge/automerge";
5
- export type CollectionHandleEvents = {
6
- doc_added: (url: AutomergeUrl) => void;
7
- };
8
- export declare class CollectionHandle extends EventEmitter<CollectionHandleEvents> {
9
- #private;
10
- get index(): Index;
11
- constructor(belay: A.beelay.Beelay, rootUrl: AutomergeUrl, entries: AutomergeUrl[]);
12
- add(url: AutomergeUrl): void;
13
- }
14
- //# sourceMappingURL=CollectionHandle.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CollectionHandle.d.ts","sourceRoot":"","sources":["../src/CollectionHandle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAW,KAAK,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAc,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,sBAAsB,CAAA;AAGhD,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAA;CACvC,CAAA;AAED,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAQxE,IAAI,KAAK,IAAI,KAAK,CAKjB;gBAGC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EACtB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,YAAY,EAAE;IAoBzB,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI;CAK7B"}
@@ -1,37 +0,0 @@
1
- import { EventEmitter } from "eventemitter3";
2
- import { parseAutomergeUrl } from "./AutomergeUrl.js";
3
- export class CollectionHandle extends EventEmitter {
4
- //#index: Index
5
- #beelay;
6
- //#ferigan: Ferigan
7
- #rootId;
8
- #rootUrl;
9
- #entries = [];
10
- get index() {
11
- return {
12
- rootUrl: this.#rootUrl,
13
- entries: this.#entries,
14
- };
15
- }
16
- constructor(belay, rootUrl, entries) {
17
- super();
18
- this.#rootUrl = rootUrl;
19
- this.#rootId = parseAutomergeUrl(rootUrl).documentId;
20
- this.#beelay = belay;
21
- this.#entries = entries;
22
- //this.#ferigan.on("indexChanged", ({indexUrl, change}) => {
23
- //if (indexUrl != this.#index.rootUrl) {
24
- //return
25
- //}
26
- //if (change.type === "add") {
27
- //this.#index.entries.push(change.url)
28
- //this.emit("doc_added", change.url as AutomergeUrl)
29
- //}
30
- //})
31
- }
32
- add(url) {
33
- this.#entries.push(url);
34
- let docId = parseAutomergeUrl(url).documentId;
35
- this.#beelay.addLink({ from: this.#rootId, to: docId });
36
- }
37
- }
package/dist/DocUrl.d.ts DELETED
@@ -1,47 +0,0 @@
1
- import {
2
- type AutomergeUrl,
3
- type BinaryDocumentId,
4
- type DocumentId,
5
- } from "./types.js"
6
- export declare const urlPrefix = "automerge:"
7
- /**
8
- * given an Automerge URL, return a decoded DocumentId (and the encoded DocumentId)
9
- *
10
- * @param url
11
- * @returns { binaryDocumentId: BinaryDocumentId, documentId: DocumentId }
12
- */
13
- export declare const parseAutomergeUrl: (url: AutomergeUrl) => {
14
- binaryDocumentId: BinaryDocumentId
15
- documentId: DocumentId
16
- }
17
- /**
18
- * Given a documentId in either canonical form, return an Automerge URL
19
- * Throws on invalid input.
20
- * Note: this is an object because we anticipate adding fields in the future.
21
- * @param { documentId: BinaryDocumentId | DocumentId }
22
- * @returns AutomergeUrl
23
- */
24
- export declare const stringifyAutomergeUrl: ({
25
- documentId,
26
- }: {
27
- documentId: DocumentId | BinaryDocumentId
28
- }) => AutomergeUrl
29
- /**
30
- * Given a string, return true if it is a valid Automerge URL
31
- * also acts as a type discriminator in Typescript.
32
- * @param str: URL candidate
33
- * @returns boolean
34
- */
35
- export declare const isValidAutomergeUrl: (str: string) => str is AutomergeUrl
36
- /**
37
- * generateAutomergeUrl produces a new AutomergeUrl.
38
- * generally only called by create(), but used in tests as well.
39
- * @returns a new Automerge URL with a random UUID documentId
40
- */
41
- export declare const generateAutomergeUrl: () => AutomergeUrl
42
- export declare const documentIdToBinary: (
43
- docId: DocumentId
44
- ) => BinaryDocumentId | undefined
45
- export declare const binaryToDocumentId: (docId: BinaryDocumentId) => DocumentId
46
- export declare const parseLegacyUUID: (str: string) => AutomergeUrl | undefined
47
- //# sourceMappingURL=DocUrl.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DocUrl.d.ts","sourceRoot":"","sources":["../src/DocUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAA;AAInB,eAAO,MAAM,SAAS,eAAe,CAAA;AAErC;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,QAAS,YAAY;;;CAIlD,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB;gBAGpB,UAAU,GAAG,gBAAgB;MACvC,YAQH,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAS,MAAM,wBAK9C,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAAO,YAGpC,CAAA;AAEJ,eAAO,MAAM,kBAAkB,UACtB,UAAU,KAChB,gBAAgB,GAAG,SACyC,CAAA;AAE/D,eAAO,MAAM,kBAAkB,UAAW,gBAAgB,KAAG,UACtB,CAAA;AAEvC,eAAO,MAAM,eAAe,QAAS,MAAM,KAAG,YAAY,GAAG,SAM5D,CAAA"}
package/dist/DocUrl.js DELETED
@@ -1,72 +0,0 @@
1
- import * as Uuid from "uuid"
2
- import bs58check from "bs58check"
3
- export const urlPrefix = "automerge:"
4
- /**
5
- * given an Automerge URL, return a decoded DocumentId (and the encoded DocumentId)
6
- *
7
- * @param url
8
- * @returns { binaryDocumentId: BinaryDocumentId, documentId: DocumentId }
9
- */
10
- export const parseAutomergeUrl = url => {
11
- const { binaryDocumentId, documentId } = parts(url)
12
- if (!binaryDocumentId) throw new Error("Invalid document URL: " + url)
13
- return { binaryDocumentId, documentId }
14
- }
15
- /**
16
- * Given a documentId in either canonical form, return an Automerge URL
17
- * Throws on invalid input.
18
- * Note: this is an object because we anticipate adding fields in the future.
19
- * @param { documentId: BinaryDocumentId | DocumentId }
20
- * @returns AutomergeUrl
21
- */
22
- export const stringifyAutomergeUrl = ({ documentId }) => {
23
- if (documentId instanceof Uint8Array)
24
- return urlPrefix + binaryToDocumentId(documentId)
25
- else if (typeof documentId === "string") {
26
- return urlPrefix + documentId
27
- }
28
- throw new Error("Invalid documentId: " + documentId)
29
- }
30
- /**
31
- * Given a string, return true if it is a valid Automerge URL
32
- * also acts as a type discriminator in Typescript.
33
- * @param str: URL candidate
34
- * @returns boolean
35
- */
36
- export const isValidAutomergeUrl = str => {
37
- if (!str.startsWith(urlPrefix)) return false
38
- const { binaryDocumentId: documentId } = parts(str)
39
- return documentId ? true : false
40
- }
41
- /**
42
- * generateAutomergeUrl produces a new AutomergeUrl.
43
- * generally only called by create(), but used in tests as well.
44
- * @returns a new Automerge URL with a random UUID documentId
45
- */
46
- export const generateAutomergeUrl = () =>
47
- stringifyAutomergeUrl({
48
- documentId: Uuid.v4(null, new Uint8Array(16)),
49
- })
50
- export const documentIdToBinary = docId => bs58check.decodeUnsafe(docId)
51
- export const binaryToDocumentId = docId => bs58check.encode(docId)
52
- export const parseLegacyUUID = str => {
53
- if (Uuid.validate(str)) {
54
- const uuid = Uuid.parse(str)
55
- return stringifyAutomergeUrl({ documentId: uuid })
56
- }
57
- return undefined
58
- }
59
- /**
60
- * parts breaks up the URL into constituent pieces,
61
- * eventually this could include things like heads, so we use this structure
62
- * we return both a binary & string-encoded version of the document ID
63
- * @param str
64
- * @returns { binaryDocumentId, documentId }
65
- */
66
- const parts = str => {
67
- const regex = new RegExp(`^${urlPrefix}(\\w+)$`)
68
- const [_, docMatch] = str.match(regex) || []
69
- const documentId = docMatch
70
- const binaryDocumentId = documentIdToBinary(documentId)
71
- return { binaryDocumentId, documentId }
72
- }
@@ -1,20 +0,0 @@
1
- import { DocumentId, PeerId } from "./index.js"
2
- import { EphemeralMessage, MessageContents } from "./network/messages.js"
3
- /** A randomly generated string created when the {@link Repo} starts up */
4
- export type SessionId = string & {
5
- __SessionId: false
6
- }
7
- export interface EphemeralDataPayload {
8
- documentId: DocumentId
9
- peerId: PeerId
10
- data: {
11
- peerId: PeerId
12
- documentId: DocumentId
13
- data: unknown
14
- }
15
- }
16
- export type EphemeralDataMessageEvents = {
17
- message: (event: MessageContents<EphemeralMessage>) => void
18
- data: (event: EphemeralDataPayload) => void
19
- }
20
- //# sourceMappingURL=EphemeralData.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EphemeralData.d.ts","sourceRoot":"","sources":["../src/EphemeralData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAGzE,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,WAAW,EAAE,KAAK,CAAA;CAAE,CAAA;AAEvD,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAA;CAChE;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAA;IAC3D,IAAI,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;CAC5C,CAAA"}
@@ -1 +0,0 @@
1
- export {}
package/dist/ferigan.d.ts DELETED
@@ -1,51 +0,0 @@
1
- import { EventEmitter } from "eventemitter3";
2
- import { MessageContents, RepoMessage } from "./network/messages.js";
3
- import { AutomergeUrl } from "./types.js";
4
- import { Repo } from "./Repo.js";
5
- export interface Ferigan extends EventEmitter<FeriganEvents> {
6
- receiveMessage(message: RepoMessage): Promise<void>;
7
- load(doc: ChangeLogId, since: ChangeHash[]): AsyncIterableIterator<Progress<ChangeLog | undefined>>;
8
- loadCollection(doc: ChangeLogId): AsyncIterableIterator<Progress<Index | undefined>>;
9
- append(doc: ChangeLogId, parents: ChangeHash[], changes: Uint8Array): Promise<void>;
10
- replace(doc: ChangeLogId, start: ChangeHash, end: ChangeHash, changes: Uint8Array): Promise<void>;
11
- }
12
- export declare function makeFerigan(repo: Repo): Ferigan;
13
- interface FeriganEvents {
14
- message: (event: {
15
- message: MessageContents;
16
- }) => void;
17
- changed: (event: {
18
- changedLog: ChangeLogId;
19
- }) => void;
20
- indexChanged: (event: {
21
- indexUrl: ChangeLogId;
22
- change: IndexChange;
23
- }) => void;
24
- }
25
- type IndexChange = {
26
- type: "add";
27
- url: AutomergeUrl;
28
- };
29
- type ChangeLogId = string;
30
- type ChangeHash = string;
31
- type ChangeLog = {
32
- start: ChangeHash;
33
- end: ChangeHash;
34
- changes: Uint8Array;
35
- };
36
- export type Progress<T> = {
37
- type: "synchronizing_index";
38
- } | {
39
- type: "synchronizing_docs";
40
- progress: number;
41
- total: number;
42
- } | {
43
- type: "done";
44
- value: T;
45
- };
46
- export type Index = {
47
- rootUrl: AutomergeUrl;
48
- entries: AutomergeUrl[];
49
- };
50
- export {};
51
- //# sourceMappingURL=ferigan.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ferigan.d.ts","sourceRoot":"","sources":["../src/ferigan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAIhC,MAAM,WAAW,OAAQ,SAAQ,YAAY,CAAC,aAAa,CAAC;IAC1D,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,IAAI,CACF,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,UAAU,EAAE,GAClB,qBAAqB,CAAC,QAAQ,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC,CAAA;IACzD,cAAc,CACZ,GAAG,EAAE,WAAW,GACf,qBAAqB,CAAC,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,CAAA;IACrD,MAAM,CACJ,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAAA;IAChB,OAAO,CACL,GAAG,EAAE,WAAW,EAChB,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,IAAI,CAAC,CAAA;CACjB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CA+G/C;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE;QAAC,OAAO,EAAE,eAAe,CAAA;KAAC,KAAK,IAAI,CAAA;IACpD,OAAO,EAAE,CAAC,KAAK,EAAE;QAAC,UAAU,EAAE,WAAW,CAAA;KAAC,KAAK,IAAI,CAAA;IACnD,YAAY,EAAE,CAAC,KAAK,EAAE;QAAC,QAAQ,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAC,KAAK,IAAI,CAAA;CAC5E;AAED,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,KAAK,CAAA;IACX,GAAG,EAAE,YAAY,CAAA;CAClB,CAAA;AAED,KAAK,WAAW,GAAG,MAAM,CAAA;AAEzB,KAAK,UAAU,GAAG,MAAM,CAAA;AAExB,KAAK,SAAS,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAA;AAE5E,MAAM,MAAM,QAAQ,CAAC,CAAC,IAClB;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GAC/B;IACA,IAAI,EAAE,oBAAoB,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd,GACC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAA;AAE9B,MAAM,MAAM,KAAK,GAAG;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAA"}