@automerge/automerge-repo 2.0.0-alpha.2 → 2.0.0-alpha.22
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 +5 -6
- package/dist/AutomergeUrl.d.ts +17 -5
- package/dist/AutomergeUrl.d.ts.map +1 -1
- package/dist/AutomergeUrl.js +71 -24
- package/dist/DocHandle.d.ts +89 -20
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +189 -28
- package/dist/FindProgress.d.ts +30 -0
- package/dist/FindProgress.d.ts.map +1 -0
- package/dist/FindProgress.js +1 -0
- package/dist/RemoteHeadsSubscriptions.d.ts +4 -5
- package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -1
- package/dist/RemoteHeadsSubscriptions.js +4 -1
- package/dist/Repo.d.ts +44 -6
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +226 -87
- package/dist/entrypoints/fullfat.d.ts +1 -0
- package/dist/entrypoints/fullfat.d.ts.map +1 -1
- package/dist/entrypoints/fullfat.js +1 -2
- package/dist/helpers/abortable.d.ts +39 -0
- package/dist/helpers/abortable.d.ts.map +1 -0
- package/dist/helpers/abortable.js +45 -0
- package/dist/helpers/bufferFromHex.d.ts +3 -0
- package/dist/helpers/bufferFromHex.d.ts.map +1 -0
- package/dist/helpers/bufferFromHex.js +13 -0
- package/dist/helpers/headsAreSame.d.ts +2 -2
- package/dist/helpers/headsAreSame.d.ts.map +1 -1
- package/dist/helpers/mergeArrays.d.ts +1 -1
- package/dist/helpers/mergeArrays.d.ts.map +1 -1
- package/dist/helpers/tests/network-adapter-tests.d.ts.map +1 -1
- package/dist/helpers/tests/network-adapter-tests.js +13 -13
- package/dist/helpers/tests/storage-adapter-tests.d.ts +2 -2
- package/dist/helpers/tests/storage-adapter-tests.d.ts.map +1 -1
- package/dist/helpers/tests/storage-adapter-tests.js +25 -48
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/storage/StorageSubsystem.d.ts +11 -1
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +20 -4
- package/dist/synchronizer/CollectionSynchronizer.d.ts +17 -3
- package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.js +43 -18
- package/dist/synchronizer/DocSynchronizer.d.ts +10 -2
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +30 -8
- package/dist/synchronizer/Synchronizer.d.ts +11 -0
- package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
- package/dist/types.d.ts +4 -1
- package/dist/types.d.ts.map +1 -1
- package/fuzz/fuzz.ts +3 -3
- package/package.json +3 -3
- package/src/AutomergeUrl.ts +101 -26
- package/src/DocHandle.ts +256 -38
- package/src/FindProgress.ts +48 -0
- package/src/RemoteHeadsSubscriptions.ts +11 -9
- package/src/Repo.ts +310 -95
- package/src/entrypoints/fullfat.ts +1 -2
- package/src/helpers/abortable.ts +61 -0
- package/src/helpers/bufferFromHex.ts +14 -0
- package/src/helpers/headsAreSame.ts +2 -2
- package/src/helpers/tests/network-adapter-tests.ts +14 -13
- package/src/helpers/tests/storage-adapter-tests.ts +44 -86
- package/src/index.ts +2 -0
- package/src/storage/StorageSubsystem.ts +29 -4
- package/src/synchronizer/CollectionSynchronizer.ts +56 -19
- package/src/synchronizer/DocSynchronizer.ts +34 -9
- package/src/synchronizer/Synchronizer.ts +14 -0
- package/src/types.ts +4 -1
- package/test/AutomergeUrl.test.ts +130 -0
- package/test/CollectionSynchronizer.test.ts +4 -4
- package/test/DocHandle.test.ts +189 -29
- package/test/DocSynchronizer.test.ts +10 -3
- package/test/Repo.test.ts +377 -191
- package/test/StorageSubsystem.test.ts +17 -0
- package/test/remoteHeads.test.ts +27 -12
package/dist/DocHandle.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as A from "@automerge/automerge/slim/next";
|
|
|
2
2
|
import debug from "debug";
|
|
3
3
|
import { EventEmitter } from "eventemitter3";
|
|
4
4
|
import { assertEvent, assign, createActor, setup, waitFor } from "xstate";
|
|
5
|
-
import { stringifyAutomergeUrl } from "./AutomergeUrl.js";
|
|
5
|
+
import { decodeHeads, encodeHeads, stringifyAutomergeUrl, } from "./AutomergeUrl.js";
|
|
6
6
|
import { encode } from "./helpers/cbor.js";
|
|
7
7
|
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
8
8
|
import { withTimeout } from "./helpers/withTimeout.js";
|
|
@@ -24,6 +24,8 @@ export class DocHandle extends EventEmitter {
|
|
|
24
24
|
#log;
|
|
25
25
|
/** The XState actor running our state machine. */
|
|
26
26
|
#machine;
|
|
27
|
+
/** If set, this handle will only show the document at these heads */
|
|
28
|
+
#fixedHeads;
|
|
27
29
|
/** The last known state of our document. */
|
|
28
30
|
#prevDocState = A.init();
|
|
29
31
|
/** How long to wait before giving up on a document. (Note that a document will be marked
|
|
@@ -38,6 +40,9 @@ export class DocHandle extends EventEmitter {
|
|
|
38
40
|
if ("timeoutDelay" in options && options.timeoutDelay) {
|
|
39
41
|
this.#timeoutDelay = options.timeoutDelay;
|
|
40
42
|
}
|
|
43
|
+
if ("heads" in options) {
|
|
44
|
+
this.#fixedHeads = options.heads;
|
|
45
|
+
}
|
|
41
46
|
const doc = A.init();
|
|
42
47
|
this.#log = debug(`automerge-repo:dochandle:${this.documentId.slice(0, 5)}`);
|
|
43
48
|
const delay = this.#timeoutDelay;
|
|
@@ -59,9 +64,12 @@ export class DocHandle extends EventEmitter {
|
|
|
59
64
|
this.emit("delete", { handle: this });
|
|
60
65
|
return { doc: A.init() };
|
|
61
66
|
}),
|
|
62
|
-
onUnavailable: () => {
|
|
63
|
-
|
|
64
|
-
},
|
|
67
|
+
onUnavailable: assign(() => {
|
|
68
|
+
return { doc: A.init() };
|
|
69
|
+
}),
|
|
70
|
+
onUnload: assign(() => {
|
|
71
|
+
return { doc: A.init() };
|
|
72
|
+
}),
|
|
65
73
|
},
|
|
66
74
|
}).createMachine({
|
|
67
75
|
/** @xstate-layout N4IgpgJg5mDOIC5QAoC2BDAxgCwJYDswBKAYgFUAFAEQEEAVAUQG0AGAXUVAAcB7WXAC64e+TiAAeiAOwAOAKwA6ACxSAzKqks1ATjlTdAGhABPRAFolAJksKN2y1KtKAbFLla5AX09G0WPISkVAwAMgyMrBxIILz8QiJikggAjCzOijKqLEqqybJyLizaRqYIFpbJtro5Uo7J2o5S3r4YOATECrgQADZgJADCAEoM9MzsYrGCwqLRSeoyCtra8pa5adquySXmDjY5ac7JljLJeepKzSB+bYGdPX0AYgCSAHJUkRN8UwmziM7HCgqyVcUnqcmScmcMm2ZV2yiyzkOx1OalUFx8V1aAQ63R46AgBCgJGGAEUyAwAMp0D7RSbxGagJKHFgKOSWJTJGRSCosCpKaEmRCqbQKU5yXINeTaer6LwY67YogKXH4wkkKgAeX6AH1hjQqABNGncL70xKIJQ5RY5BHOJag6wwpRyEWImQVeT1aWrVSXBXtJUqgn4Ik0ADqNCedG1L3CYY1gwA0saYqbpuaEG4pKLksKpFDgcsCjDhTnxTKpTLdH6sQGFOgAO7oKYhl5gAQNngAJwA1iRY3R40ndSNDSm6enfpm5BkWAVkvy7bpuTCKq7ndZnfVeSwuTX-HWu2AAI4AVzgQhD6q12rILxoADVIyEaAAhMLjtM-RmIE4LVSQi4nLLDIGzOCWwLKA0cgyLBoFWNy+43B0R5nheaqajqepjuMtJfgyEh-FoixqMCoKqOyhzgYKCDOq6UIeuCSxHOoSGKgop74OgABuzbdOgABGvTXlho5GrhJpxJOP4pLulT6KoMhpJY2hzsWNF0QobqMV6LG+pc+A8BAcBiP6gSfFJ36EQgKksksKxrHamwwmY7gLKB85QjBzoAWxdZdL0FnfARST8ooLC7qoTnWBU4pyC5ViVMKBQaHUDQuM4fm3EGhJBWaU7-CysEAUp3LpEpWw0WYRw2LmqzgqciIsCxWUdI2zaXlAbYdt2PZ5dJ1n5jY2iJY1ikOIcMJHCyUWHC62hRZkUVNPKta3Kh56wJ1-VWUyzhFc64JWJCtQNBBzhQW4cHwbsrVKpxPF8YJgV4ZZIWIKkiKiiNSkqZYWjzCWaQ5hFh0AcCuR3QoR74qUknBRmzholpv3OkpRQNNRpTzaKTWKbIWR5FDxm9AIkA7e9skUYCWayLILBZGoLkUSKbIyIdpxHPoyTeN4QA */
|
|
@@ -71,6 +79,7 @@ export class DocHandle extends EventEmitter {
|
|
|
71
79
|
context: { documentId, doc },
|
|
72
80
|
on: {
|
|
73
81
|
UPDATE: { actions: "onUpdate" },
|
|
82
|
+
UNLOAD: ".unloaded",
|
|
74
83
|
DELETE: ".deleted",
|
|
75
84
|
},
|
|
76
85
|
states: {
|
|
@@ -98,6 +107,12 @@ export class DocHandle extends EventEmitter {
|
|
|
98
107
|
on: { DOC_READY: "ready" },
|
|
99
108
|
},
|
|
100
109
|
ready: {},
|
|
110
|
+
unloaded: {
|
|
111
|
+
entry: "onUnload",
|
|
112
|
+
on: {
|
|
113
|
+
RELOAD: "loading",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
101
116
|
deleted: { entry: "onDelete", type: "final" },
|
|
102
117
|
},
|
|
103
118
|
});
|
|
@@ -113,7 +128,7 @@ export class DocHandle extends EventEmitter {
|
|
|
113
128
|
});
|
|
114
129
|
// Start the machine, and send a create or find event to get things going
|
|
115
130
|
this.#machine.start();
|
|
116
|
-
this
|
|
131
|
+
this.begin();
|
|
117
132
|
}
|
|
118
133
|
// PRIVATE
|
|
119
134
|
/** Returns the current document, regardless of state */
|
|
@@ -140,7 +155,7 @@ export class DocHandle extends EventEmitter {
|
|
|
140
155
|
#checkForChanges(before, after) {
|
|
141
156
|
const beforeHeads = A.getHeads(before);
|
|
142
157
|
const afterHeads = A.getHeads(after);
|
|
143
|
-
const docChanged = !headsAreSame(afterHeads, beforeHeads);
|
|
158
|
+
const docChanged = !headsAreSame(encodeHeads(afterHeads), encodeHeads(beforeHeads));
|
|
144
159
|
if (docChanged) {
|
|
145
160
|
this.emit("heads-changed", { handle: this, doc: after });
|
|
146
161
|
const patches = A.diff(after, beforeHeads, afterHeads);
|
|
@@ -163,7 +178,10 @@ export class DocHandle extends EventEmitter {
|
|
|
163
178
|
/** Our documentId in Automerge URL form.
|
|
164
179
|
*/
|
|
165
180
|
get url() {
|
|
166
|
-
return stringifyAutomergeUrl({
|
|
181
|
+
return stringifyAutomergeUrl({
|
|
182
|
+
documentId: this.documentId,
|
|
183
|
+
heads: this.#fixedHeads,
|
|
184
|
+
});
|
|
167
185
|
}
|
|
168
186
|
/**
|
|
169
187
|
* @returns true if the document is ready for accessing or changes.
|
|
@@ -172,6 +190,13 @@ export class DocHandle extends EventEmitter {
|
|
|
172
190
|
* peers. We do not currently have an equivalent `whenSynced()`.
|
|
173
191
|
*/
|
|
174
192
|
isReady = () => this.inState(["ready"]);
|
|
193
|
+
/**
|
|
194
|
+
* @returns true if the document has been unloaded.
|
|
195
|
+
*
|
|
196
|
+
* Unloaded documents are freed from memory but not removed from local storage. It's not currently
|
|
197
|
+
* possible at runtime to reload an unloaded document.
|
|
198
|
+
*/
|
|
199
|
+
isUnloaded = () => this.inState(["unloaded"]);
|
|
175
200
|
/**
|
|
176
201
|
* @returns true if the document has been marked as deleted.
|
|
177
202
|
*
|
|
@@ -209,7 +234,7 @@ export class DocHandle extends EventEmitter {
|
|
|
209
234
|
* This is the recommended way to access a handle's document. Note that this waits for the handle
|
|
210
235
|
* to be ready if necessary. If loading (or synchronization) fails, this will never resolve.
|
|
211
236
|
*/
|
|
212
|
-
async
|
|
237
|
+
async legacyAsyncDoc(
|
|
213
238
|
/** states to wait for, such as "LOADING". mostly for internal use. */
|
|
214
239
|
awaitStates = ["ready", "unavailable"]) {
|
|
215
240
|
try {
|
|
@@ -224,23 +249,26 @@ export class DocHandle extends EventEmitter {
|
|
|
224
249
|
return !this.isUnavailable() ? this.#doc : undefined;
|
|
225
250
|
}
|
|
226
251
|
/**
|
|
227
|
-
*
|
|
228
|
-
* undefined. Consider using `await handle.doc()` instead. Check `isReady()`, or use `whenReady()`
|
|
229
|
-
* if you want to make sure loading is complete first.
|
|
252
|
+
* Returns the current state of the Automerge document this handle manages.
|
|
230
253
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
254
|
+
* @returns the current document
|
|
255
|
+
* @throws on deleted and unavailable documents
|
|
233
256
|
*
|
|
234
|
-
* Note that `undefined` is not a valid Automerge document, so the return from this function is
|
|
235
|
-
* unambigous.
|
|
236
|
-
*
|
|
237
|
-
* @returns the current document, or undefined if the document is not ready.
|
|
238
257
|
*/
|
|
239
|
-
|
|
258
|
+
doc() {
|
|
240
259
|
if (!this.isReady())
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
return this.#doc;
|
|
260
|
+
throw new Error("DocHandle is not ready");
|
|
261
|
+
if (this.#fixedHeads) {
|
|
262
|
+
return A.view(this.#doc, decodeHeads(this.#fixedHeads));
|
|
263
|
+
}
|
|
264
|
+
return this.#doc;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
*
|
|
268
|
+
* @deprecated */
|
|
269
|
+
docSync() {
|
|
270
|
+
console.warn("docSync is deprecated. Use doc() instead. This function will be removed as part of the 2.0 release.");
|
|
271
|
+
return this.doc();
|
|
244
272
|
}
|
|
245
273
|
/**
|
|
246
274
|
* Returns the current "heads" of the document, akin to a git commit.
|
|
@@ -248,10 +276,120 @@ export class DocHandle extends EventEmitter {
|
|
|
248
276
|
* @returns the current document's heads, or undefined if the document is not ready
|
|
249
277
|
*/
|
|
250
278
|
heads() {
|
|
279
|
+
if (!this.isReady())
|
|
280
|
+
throw new Error("DocHandle is not ready");
|
|
281
|
+
if (this.#fixedHeads) {
|
|
282
|
+
return this.#fixedHeads;
|
|
283
|
+
}
|
|
284
|
+
return encodeHeads(A.getHeads(this.#doc));
|
|
285
|
+
}
|
|
286
|
+
begin() {
|
|
287
|
+
this.#machine.send({ type: BEGIN });
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Returns an array of all past "heads" for the document in topological order.
|
|
291
|
+
*
|
|
292
|
+
* @remarks
|
|
293
|
+
* A point-in-time in an automerge document is an *array* of heads since there may be
|
|
294
|
+
* concurrent edits. This API just returns a topologically sorted history of all edits
|
|
295
|
+
* so every previous entry will be (in some sense) before later ones, but the set of all possible
|
|
296
|
+
* history views would be quite large under concurrency (every thing in each branch against each other).
|
|
297
|
+
* There might be a clever way to think about this, but we haven't found it yet, so for now at least
|
|
298
|
+
* we present a single traversable view which excludes concurrency.
|
|
299
|
+
* @returns UrlHeads[] - The individual heads for every change in the document. Each item is a tagged string[1].
|
|
300
|
+
*/
|
|
301
|
+
history() {
|
|
302
|
+
if (!this.isReady()) {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
// This just returns all the heads as individual strings.
|
|
306
|
+
return A.topoHistoryTraversal(this.#doc).map(h => encodeHeads([h]));
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Creates a fixed "view" of an automerge document at the given point in time represented
|
|
310
|
+
* by the `heads` passed in. The return value is the same type as doc() and will return
|
|
311
|
+
* undefined if the object hasn't finished loading.
|
|
312
|
+
*
|
|
313
|
+
* @remarks
|
|
314
|
+
* Note that our Typescript types do not consider change over time and the current version
|
|
315
|
+
* of Automerge doesn't check types at runtime, so if you go back to an old set of heads
|
|
316
|
+
* that doesn't match the heads here, Typescript will not save you.
|
|
317
|
+
*
|
|
318
|
+
* @argument heads - The heads to view the document at. See history().
|
|
319
|
+
* @returns DocHandle<T> at the time of `heads`
|
|
320
|
+
*/
|
|
321
|
+
view(heads) {
|
|
322
|
+
if (!this.isReady()) {
|
|
323
|
+
throw new Error(`DocHandle#${this.documentId} is not ready. Check \`handle.isReady()\` before calling view().`);
|
|
324
|
+
}
|
|
325
|
+
// Create a new handle with the same documentId but fixed heads
|
|
326
|
+
const handle = new DocHandle(this.documentId, {
|
|
327
|
+
heads,
|
|
328
|
+
timeoutDelay: this.#timeoutDelay,
|
|
329
|
+
});
|
|
330
|
+
handle.update(() => A.clone(this.#doc));
|
|
331
|
+
handle.doneLoading();
|
|
332
|
+
return handle;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Returns a set of Patch operations that will move a materialized document from one state to another
|
|
336
|
+
* if applied.
|
|
337
|
+
*
|
|
338
|
+
* @remarks
|
|
339
|
+
* We allow specifying either:
|
|
340
|
+
* - Two sets of heads to compare directly
|
|
341
|
+
* - A single set of heads to compare against our current heads
|
|
342
|
+
* - Another DocHandle to compare against (which must share history with this document)
|
|
343
|
+
*
|
|
344
|
+
* @throws Error if the documents don't share history or if either document is not ready
|
|
345
|
+
* @returns Automerge patches that go from one document state to the other
|
|
346
|
+
*/
|
|
347
|
+
diff(first, second) {
|
|
348
|
+
if (!this.isReady()) {
|
|
349
|
+
throw new Error(`DocHandle#${this.documentId} is not ready. Check \`handle.isReady()\` before calling diff().`);
|
|
350
|
+
}
|
|
351
|
+
const doc = this.#doc;
|
|
352
|
+
if (!doc)
|
|
353
|
+
throw new Error("Document not available");
|
|
354
|
+
// If first argument is a DocHandle
|
|
355
|
+
if (first instanceof DocHandle) {
|
|
356
|
+
if (!first.isReady()) {
|
|
357
|
+
throw new Error("Cannot diff against a handle that isn't ready");
|
|
358
|
+
}
|
|
359
|
+
const otherHeads = first.heads();
|
|
360
|
+
if (!otherHeads)
|
|
361
|
+
throw new Error("Other document's heads not available");
|
|
362
|
+
// Create a temporary merged doc to verify shared history and compute diff
|
|
363
|
+
const mergedDoc = A.merge(A.clone(doc), first.doc());
|
|
364
|
+
// Use the merged doc to compute the diff
|
|
365
|
+
return A.diff(mergedDoc, decodeHeads(this.heads()), decodeHeads(otherHeads));
|
|
366
|
+
}
|
|
367
|
+
// Otherwise treat as heads
|
|
368
|
+
const from = second ? first : (this.heads() || []);
|
|
369
|
+
const to = second ? second : first;
|
|
370
|
+
return A.diff(doc, decodeHeads(from), decodeHeads(to));
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* `metadata(head?)` allows you to look at the metadata for a change
|
|
374
|
+
* this can be used to build history graphs to find commit messages and edit times.
|
|
375
|
+
* this interface.
|
|
376
|
+
*
|
|
377
|
+
* @remarks
|
|
378
|
+
* I'm really not convinced this is the right way to surface this information so
|
|
379
|
+
* I'm leaving this API "hidden".
|
|
380
|
+
*
|
|
381
|
+
* @hidden
|
|
382
|
+
*/
|
|
383
|
+
metadata(change) {
|
|
251
384
|
if (!this.isReady()) {
|
|
252
385
|
return undefined;
|
|
253
386
|
}
|
|
254
|
-
|
|
387
|
+
if (!change) {
|
|
388
|
+
change = this.heads()[0];
|
|
389
|
+
}
|
|
390
|
+
// we return undefined instead of null by convention in this API
|
|
391
|
+
return (A.inspectChange(this.#doc, decodeHeads([change])[0]) ||
|
|
392
|
+
undefined);
|
|
255
393
|
}
|
|
256
394
|
/**
|
|
257
395
|
* `update` is called any time we have a new document state; could be
|
|
@@ -301,6 +439,9 @@ export class DocHandle extends EventEmitter {
|
|
|
301
439
|
if (!this.isReady()) {
|
|
302
440
|
throw new Error(`DocHandle#${this.documentId} is in ${this.state} and not ready. Check \`handle.isReady()\` before accessing the document.`);
|
|
303
441
|
}
|
|
442
|
+
if (this.#fixedHeads) {
|
|
443
|
+
throw new Error(`DocHandle#${this.documentId} is in view-only mode at specific heads. Use clone() to create a new document from this state.`);
|
|
444
|
+
}
|
|
304
445
|
this.#machine.send({
|
|
305
446
|
type: UPDATE,
|
|
306
447
|
payload: { callback: doc => A.change(doc, options, callback) },
|
|
@@ -315,13 +456,18 @@ export class DocHandle extends EventEmitter {
|
|
|
315
456
|
if (!this.isReady()) {
|
|
316
457
|
throw new Error(`DocHandle#${this.documentId} is not ready. Check \`handle.isReady()\` before accessing the document.`);
|
|
317
458
|
}
|
|
459
|
+
if (this.#fixedHeads) {
|
|
460
|
+
throw new Error(`DocHandle#${this.documentId} is in view-only mode at specific heads. Use clone() to create a new document from this state.`);
|
|
461
|
+
}
|
|
318
462
|
let resultHeads = undefined;
|
|
319
463
|
this.#machine.send({
|
|
320
464
|
type: UPDATE,
|
|
321
465
|
payload: {
|
|
322
466
|
callback: doc => {
|
|
323
|
-
const result = A.changeAt(doc, heads, options, callback);
|
|
324
|
-
resultHeads = result.newHeads
|
|
467
|
+
const result = A.changeAt(doc, decodeHeads(heads), options, callback);
|
|
468
|
+
resultHeads = result.newHeads
|
|
469
|
+
? encodeHeads(result.newHeads)
|
|
470
|
+
: undefined;
|
|
325
471
|
return result.newDoc;
|
|
326
472
|
},
|
|
327
473
|
},
|
|
@@ -343,10 +489,10 @@ export class DocHandle extends EventEmitter {
|
|
|
343
489
|
if (!this.isReady() || !otherHandle.isReady()) {
|
|
344
490
|
throw new Error("Both handles must be ready to merge");
|
|
345
491
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
throw new Error("The document to be merged in is falsy, aborting.");
|
|
492
|
+
if (this.#fixedHeads) {
|
|
493
|
+
throw new Error(`DocHandle#${this.documentId} is in view-only mode at specific heads. Use clone() to create a new document from this state.`);
|
|
349
494
|
}
|
|
495
|
+
const mergingDoc = otherHandle.doc();
|
|
350
496
|
this.update(doc => {
|
|
351
497
|
return A.merge(doc, mergingDoc);
|
|
352
498
|
});
|
|
@@ -365,6 +511,14 @@ export class DocHandle extends EventEmitter {
|
|
|
365
511
|
if (this.#state === "loading")
|
|
366
512
|
this.#machine.send({ type: REQUEST });
|
|
367
513
|
}
|
|
514
|
+
/** Called by the repo to free memory used by the document. */
|
|
515
|
+
unload() {
|
|
516
|
+
this.#machine.send({ type: UNLOAD });
|
|
517
|
+
}
|
|
518
|
+
/** Called by the repo to reuse an unloaded handle. */
|
|
519
|
+
reload() {
|
|
520
|
+
this.#machine.send({ type: RELOAD });
|
|
521
|
+
}
|
|
368
522
|
/** Called by the repo when the document is deleted. */
|
|
369
523
|
delete() {
|
|
370
524
|
this.#machine.send({ type: DELETE });
|
|
@@ -382,6 +536,9 @@ export class DocHandle extends EventEmitter {
|
|
|
382
536
|
data: encode(message),
|
|
383
537
|
});
|
|
384
538
|
}
|
|
539
|
+
metrics() {
|
|
540
|
+
return A.stats(this.#doc);
|
|
541
|
+
}
|
|
385
542
|
}
|
|
386
543
|
// STATE MACHINE TYPES & CONSTANTS
|
|
387
544
|
// state
|
|
@@ -397,16 +554,20 @@ export const HandleState = {
|
|
|
397
554
|
REQUESTING: "requesting",
|
|
398
555
|
/** The document is available */
|
|
399
556
|
READY: "ready",
|
|
557
|
+
/** The document has been unloaded from the handle, to free memory usage */
|
|
558
|
+
UNLOADED: "unloaded",
|
|
400
559
|
/** The document has been deleted from the repo */
|
|
401
560
|
DELETED: "deleted",
|
|
402
561
|
/** The document was not available in storage or from any connected peers */
|
|
403
562
|
UNAVAILABLE: "unavailable",
|
|
404
563
|
};
|
|
405
|
-
export const { IDLE, LOADING, REQUESTING, READY, DELETED, UNAVAILABLE } = HandleState;
|
|
564
|
+
export const { IDLE, LOADING, REQUESTING, READY, UNLOADED, DELETED, UNAVAILABLE, } = HandleState;
|
|
406
565
|
const BEGIN = "BEGIN";
|
|
407
566
|
const REQUEST = "REQUEST";
|
|
408
567
|
const DOC_READY = "DOC_READY";
|
|
409
568
|
const UPDATE = "UPDATE";
|
|
569
|
+
const UNLOAD = "UNLOAD";
|
|
570
|
+
const RELOAD = "RELOAD";
|
|
410
571
|
const DELETE = "DELETE";
|
|
411
572
|
const TIMEOUT = "TIMEOUT";
|
|
412
573
|
const DOC_UNAVAILABLE = "DOC_UNAVAILABLE";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DocHandle } from "./DocHandle.js";
|
|
2
|
+
export type FindProgressState = "loading" | "ready" | "failed" | "aborted" | "unavailable";
|
|
3
|
+
interface FindProgressBase<T> {
|
|
4
|
+
state: FindProgressState;
|
|
5
|
+
handle: DocHandle<T>;
|
|
6
|
+
}
|
|
7
|
+
interface FindProgressLoading<T> extends FindProgressBase<T> {
|
|
8
|
+
state: "loading";
|
|
9
|
+
progress: number;
|
|
10
|
+
}
|
|
11
|
+
interface FindProgressReady<T> extends FindProgressBase<T> {
|
|
12
|
+
state: "ready";
|
|
13
|
+
}
|
|
14
|
+
interface FindProgressFailed<T> extends FindProgressBase<T> {
|
|
15
|
+
state: "failed";
|
|
16
|
+
error: Error;
|
|
17
|
+
}
|
|
18
|
+
interface FindProgressUnavailable<T> extends FindProgressBase<T> {
|
|
19
|
+
state: "unavailable";
|
|
20
|
+
}
|
|
21
|
+
interface FindProgressAborted<T> extends FindProgressBase<T> {
|
|
22
|
+
state: "aborted";
|
|
23
|
+
}
|
|
24
|
+
export type FindProgress<T> = FindProgressLoading<T> | FindProgressReady<T> | FindProgressFailed<T> | FindProgressUnavailable<T> | FindProgressAborted<T>;
|
|
25
|
+
export type FindProgressWithMethods<T> = FindProgress<T> & {
|
|
26
|
+
next: () => Promise<FindProgressWithMethods<T>>;
|
|
27
|
+
untilReady: (allowableStates: string[]) => Promise<DocHandle<T>>;
|
|
28
|
+
};
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=FindProgress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FindProgress.d.ts","sourceRoot":"","sources":["../src/FindProgress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,OAAO,GACP,QAAQ,GACR,SAAS,GACT,aAAa,CAAA;AAEjB,UAAU,gBAAgB,CAAC,CAAC;IAC1B,KAAK,EAAE,iBAAiB,CAAA;IACxB,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;CACrB;AAED,UAAU,mBAAmB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IAC1D,KAAK,EAAE,SAAS,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,UAAU,iBAAiB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IACxD,KAAK,EAAE,OAAO,CAAA;CACf;AAED,UAAU,kBAAkB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IACzD,KAAK,EAAE,QAAQ,CAAA;IACf,KAAK,EAAE,KAAK,CAAA;CACb;AAED,UAAU,uBAAuB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IAC9D,KAAK,EAAE,aAAa,CAAA;CACrB;AAED,UAAU,mBAAmB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IAC1D,KAAK,EAAE,SAAS,CAAA;CACjB;AAED,MAAM,MAAM,YAAY,CAAC,CAAC,IACtB,mBAAmB,CAAC,CAAC,CAAC,GACtB,iBAAiB,CAAC,CAAC,CAAC,GACpB,kBAAkB,CAAC,CAAC,CAAC,GACrB,uBAAuB,CAAC,CAAC,CAAC,GAC1B,mBAAmB,CAAC,CAAC,CAAC,CAAA;AAE1B,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG;IACzD,IAAI,EAAE,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAA;IAE/C,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;CACjE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import { next as A } from "@automerge/automerge/slim";
|
|
2
1
|
import { EventEmitter } from "eventemitter3";
|
|
3
|
-
import { DocumentId, PeerId } from "./types.js";
|
|
2
|
+
import { DocumentId, PeerId, UrlHeads } from "./types.js";
|
|
4
3
|
import { RemoteHeadsChanged, RemoteSubscriptionControlMessage } from "./network/messages.js";
|
|
5
4
|
import { StorageId } from "./index.js";
|
|
6
5
|
export type RemoteHeadsSubscriptionEventPayload = {
|
|
7
6
|
documentId: DocumentId;
|
|
8
7
|
storageId: StorageId;
|
|
9
|
-
remoteHeads:
|
|
8
|
+
remoteHeads: UrlHeads;
|
|
10
9
|
timestamp: number;
|
|
11
10
|
};
|
|
12
11
|
export type NotifyRemoteHeadsPayload = {
|
|
13
12
|
targetId: PeerId;
|
|
14
13
|
documentId: DocumentId;
|
|
15
14
|
storageId: StorageId;
|
|
16
|
-
heads:
|
|
15
|
+
heads: UrlHeads;
|
|
17
16
|
timestamp: number;
|
|
18
17
|
};
|
|
19
18
|
type RemoteHeadsSubscriptionEvents = {
|
|
@@ -33,7 +32,7 @@ export declare class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSu
|
|
|
33
32
|
/** A peer we are not directly connected to has changed their heads */
|
|
34
33
|
handleRemoteHeads(msg: RemoteHeadsChanged): void;
|
|
35
34
|
/** A peer we are directly connected to has updated their heads */
|
|
36
|
-
handleImmediateRemoteHeadsChanged(documentId: DocumentId, storageId: StorageId, heads:
|
|
35
|
+
handleImmediateRemoteHeadsChanged(documentId: DocumentId, storageId: StorageId, heads: UrlHeads): void;
|
|
37
36
|
addGenerousPeer(peerId: PeerId): void;
|
|
38
37
|
removePeer(peerId: PeerId): void;
|
|
39
38
|
subscribePeerToDoc(peerId: PeerId, documentId: DocumentId): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteHeadsSubscriptions.d.ts","sourceRoot":"","sources":["../src/RemoteHeadsSubscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"RemoteHeadsSubscriptions.d.ts","sourceRoot":"","sources":["../src/RemoteHeadsSubscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EACL,kBAAkB,EAClB,gCAAgC,EACjC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAItC,MAAM,MAAM,mCAAmC,GAAG;IAChD,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,QAAQ,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAGD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,QAAQ,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,6BAA6B,GAAG;IACnC,sBAAsB,EAAE,CAAC,OAAO,EAAE,mCAAmC,KAAK,IAAI,CAAA;IAC9E,oBAAoB,EAAE,CAAC,OAAO,EAAE;QAC9B,KAAK,EAAE,MAAM,EAAE,CAAA;QACf,GAAG,CAAC,EAAE,SAAS,EAAE,CAAA;QACjB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;KACrB,KAAK,IAAI,CAAA;IACV,qBAAqB,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAA;CACnE,CAAA;AAED,qBAAa,wBAAyB,SAAQ,YAAY,CAAC,6BAA6B,CAAC;;IAcvF,kBAAkB,CAAC,OAAO,EAAE,SAAS,EAAE;IAkBvC,sBAAsB,CAAC,OAAO,EAAE,SAAS,EAAE;IAsB3C,oBAAoB,CAAC,OAAO,EAAE,gCAAgC;IA0E9D,sEAAsE;IACtE,iBAAiB,CAAC,GAAG,EAAE,kBAAkB;IAgDzC,kEAAkE;IAClE,iCAAiC,CAC/B,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,QAAQ;IAgCjB,eAAe,CAAC,MAAM,EAAE,MAAM;IAwB9B,UAAU,CAAC,MAAM,EAAE,MAAM;IA2BzB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;CAuE1D"}
|
|
@@ -270,7 +270,10 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
270
270
|
continue;
|
|
271
271
|
}
|
|
272
272
|
else {
|
|
273
|
-
remote.set(storageId, {
|
|
273
|
+
remote.set(storageId, {
|
|
274
|
+
timestamp,
|
|
275
|
+
heads: heads,
|
|
276
|
+
});
|
|
274
277
|
changedHeads.push({
|
|
275
278
|
documentId,
|
|
276
279
|
storageId: storageId,
|
package/dist/Repo.d.ts
CHANGED
|
@@ -5,7 +5,11 @@ import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
|
|
|
5
5
|
import { StorageAdapterInterface } from "./storage/StorageAdapterInterface.js";
|
|
6
6
|
import { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
7
7
|
import { StorageId } from "./storage/types.js";
|
|
8
|
-
import
|
|
8
|
+
import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
|
|
9
|
+
import { DocSyncMetrics } from "./synchronizer/Synchronizer.js";
|
|
10
|
+
import type { AnyDocumentId, AutomergeUrl, DocumentId, PeerId } from "./types.js";
|
|
11
|
+
import { AbortOptions } from "./helpers/abortable.js";
|
|
12
|
+
import { FindProgress, FindProgressWithMethods } from "./FindProgress.js";
|
|
9
13
|
/** A Repo is a collection of documents with networking, syncing, and storage capabilities. */
|
|
10
14
|
/** The `Repo` is the main entry point of this library
|
|
11
15
|
*
|
|
@@ -23,13 +27,15 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
23
27
|
/** The debounce rate is adjustable on the repo. */
|
|
24
28
|
/** @hidden */
|
|
25
29
|
saveDebounceRate: number;
|
|
30
|
+
/** @hidden */
|
|
31
|
+
synchronizer: CollectionSynchronizer;
|
|
26
32
|
/** By default, we share generously with all peers. */
|
|
27
33
|
/** @hidden */
|
|
28
34
|
sharePolicy: SharePolicy;
|
|
29
35
|
/** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
|
|
30
36
|
/** @hidden */
|
|
31
37
|
peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
|
|
32
|
-
constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, }?: RepoConfig);
|
|
38
|
+
constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, denylist, }?: RepoConfig);
|
|
33
39
|
/** Returns all the handles we have cached. */
|
|
34
40
|
get handles(): Record<DocumentId, DocHandle<any>>;
|
|
35
41
|
/** Returns a list of all connected peer ids */
|
|
@@ -53,17 +59,17 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
53
59
|
* Any peers this `Repo` is connected to for whom `sharePolicy` returns `true` will
|
|
54
60
|
* be notified of the newly created DocHandle.
|
|
55
61
|
*
|
|
56
|
-
* @throws if the cloned handle is not yet ready or if
|
|
57
|
-
* `clonedHandle.docSync()` returns `undefined` (i.e. the handle is unavailable).
|
|
58
62
|
*/
|
|
59
63
|
clone<T>(clonedHandle: DocHandle<T>): DocHandle<T>;
|
|
64
|
+
findWithProgress<T>(id: AnyDocumentId, options?: AbortOptions): FindProgressWithMethods<T> | FindProgress<T>;
|
|
65
|
+
find<T>(id: AnyDocumentId, options?: RepoFindOptions & AbortOptions): Promise<DocHandle<T>>;
|
|
60
66
|
/**
|
|
61
67
|
* Retrieves a document by id. It gets data from the local system, but also emits a `document`
|
|
62
68
|
* event to advertise interest in the document.
|
|
63
69
|
*/
|
|
64
|
-
|
|
70
|
+
findClassic<T>(
|
|
65
71
|
/** The url or documentId of the handle to retrieve */
|
|
66
|
-
id: AnyDocumentId): DocHandle<T
|
|
72
|
+
id: AnyDocumentId, options?: RepoFindOptions & AbortOptions): Promise<DocHandle<T>>;
|
|
67
73
|
delete(
|
|
68
74
|
/** The url or documentId of the handle to delete */
|
|
69
75
|
id: AnyDocumentId): void;
|
|
@@ -89,7 +95,19 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
89
95
|
* @returns Promise<void>
|
|
90
96
|
*/
|
|
91
97
|
flush(documents?: DocumentId[]): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Removes a DocHandle from the handleCache.
|
|
100
|
+
* @hidden this API is experimental and may change.
|
|
101
|
+
* @param documentId - documentId of the DocHandle to remove from handleCache, if present in cache.
|
|
102
|
+
* @returns Promise<void>
|
|
103
|
+
*/
|
|
104
|
+
removeFromCache(documentId: DocumentId): Promise<void>;
|
|
92
105
|
shutdown(): Promise<void>;
|
|
106
|
+
metrics(): {
|
|
107
|
+
documents: {
|
|
108
|
+
[key: string]: any;
|
|
109
|
+
};
|
|
110
|
+
};
|
|
93
111
|
}
|
|
94
112
|
export interface RepoConfig {
|
|
95
113
|
/** Our unique identifier */
|
|
@@ -110,6 +128,12 @@ export interface RepoConfig {
|
|
|
110
128
|
* Whether to enable the experimental remote heads gossiping feature
|
|
111
129
|
*/
|
|
112
130
|
enableRemoteHeadsGossiping?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* A list of automerge URLs which should never be loaded regardless of what
|
|
133
|
+
* messages are received or what the share policy is. This is useful to avoid
|
|
134
|
+
* loading documents that are known to be too resource intensive.
|
|
135
|
+
*/
|
|
136
|
+
denylist?: AutomergeUrl[];
|
|
113
137
|
}
|
|
114
138
|
/** A function that determines whether we should share a document with a peer
|
|
115
139
|
*
|
|
@@ -127,6 +151,10 @@ export interface RepoEvents {
|
|
|
127
151
|
"delete-document": (arg: DeleteDocumentPayload) => void;
|
|
128
152
|
/** A document was marked as unavailable (we don't have it and none of our peers have it) */
|
|
129
153
|
"unavailable-document": (arg: DeleteDocumentPayload) => void;
|
|
154
|
+
"doc-metrics": (arg: DocMetrics) => void;
|
|
155
|
+
}
|
|
156
|
+
export interface RepoFindOptions {
|
|
157
|
+
allowableStates?: string[];
|
|
130
158
|
}
|
|
131
159
|
export interface DocumentPayload {
|
|
132
160
|
handle: DocHandle<any>;
|
|
@@ -134,4 +162,14 @@ export interface DocumentPayload {
|
|
|
134
162
|
export interface DeleteDocumentPayload {
|
|
135
163
|
documentId: DocumentId;
|
|
136
164
|
}
|
|
165
|
+
export type DocMetrics = DocSyncMetrics | {
|
|
166
|
+
type: "doc-loaded";
|
|
167
|
+
documentId: DocumentId;
|
|
168
|
+
durationMillis: number;
|
|
169
|
+
numOps: number;
|
|
170
|
+
numChanges: number;
|
|
171
|
+
} | {
|
|
172
|
+
type: "doc-denied";
|
|
173
|
+
documentId: DocumentId;
|
|
174
|
+
};
|
|
137
175
|
//# sourceMappingURL=Repo.d.ts.map
|
package/dist/Repo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
|