@automerge/automerge-repo 2.0.0-alpha.2 → 2.0.0-alpha.20

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/AutomergeUrl.d.ts +17 -5
  2. package/dist/AutomergeUrl.d.ts.map +1 -1
  3. package/dist/AutomergeUrl.js +71 -24
  4. package/dist/DocHandle.d.ts +80 -8
  5. package/dist/DocHandle.d.ts.map +1 -1
  6. package/dist/DocHandle.js +181 -10
  7. package/dist/RemoteHeadsSubscriptions.d.ts +4 -5
  8. package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -1
  9. package/dist/RemoteHeadsSubscriptions.js +4 -1
  10. package/dist/Repo.d.ts +35 -2
  11. package/dist/Repo.d.ts.map +1 -1
  12. package/dist/Repo.js +112 -70
  13. package/dist/entrypoints/fullfat.d.ts +1 -0
  14. package/dist/entrypoints/fullfat.d.ts.map +1 -1
  15. package/dist/entrypoints/fullfat.js +1 -2
  16. package/dist/helpers/bufferFromHex.d.ts +3 -0
  17. package/dist/helpers/bufferFromHex.d.ts.map +1 -0
  18. package/dist/helpers/bufferFromHex.js +13 -0
  19. package/dist/helpers/headsAreSame.d.ts +2 -2
  20. package/dist/helpers/headsAreSame.d.ts.map +1 -1
  21. package/dist/helpers/mergeArrays.d.ts +1 -1
  22. package/dist/helpers/mergeArrays.d.ts.map +1 -1
  23. package/dist/helpers/tests/storage-adapter-tests.d.ts +2 -2
  24. package/dist/helpers/tests/storage-adapter-tests.d.ts.map +1 -1
  25. package/dist/helpers/tests/storage-adapter-tests.js +25 -48
  26. package/dist/index.d.ts +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/storage/StorageSubsystem.d.ts +11 -1
  30. package/dist/storage/StorageSubsystem.d.ts.map +1 -1
  31. package/dist/storage/StorageSubsystem.js +20 -4
  32. package/dist/synchronizer/CollectionSynchronizer.d.ts +15 -2
  33. package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
  34. package/dist/synchronizer/CollectionSynchronizer.js +29 -8
  35. package/dist/synchronizer/DocSynchronizer.d.ts +7 -0
  36. package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
  37. package/dist/synchronizer/DocSynchronizer.js +14 -0
  38. package/dist/synchronizer/Synchronizer.d.ts +11 -0
  39. package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
  40. package/dist/types.d.ts +4 -1
  41. package/dist/types.d.ts.map +1 -1
  42. package/package.json +3 -3
  43. package/src/AutomergeUrl.ts +101 -26
  44. package/src/DocHandle.ts +245 -20
  45. package/src/RemoteHeadsSubscriptions.ts +11 -9
  46. package/src/Repo.ts +163 -68
  47. package/src/entrypoints/fullfat.ts +1 -2
  48. package/src/helpers/bufferFromHex.ts +14 -0
  49. package/src/helpers/headsAreSame.ts +2 -2
  50. package/src/helpers/tests/storage-adapter-tests.ts +44 -86
  51. package/src/index.ts +2 -0
  52. package/src/storage/StorageSubsystem.ts +29 -4
  53. package/src/synchronizer/CollectionSynchronizer.ts +42 -9
  54. package/src/synchronizer/DocSynchronizer.ts +15 -0
  55. package/src/synchronizer/Synchronizer.ts +14 -0
  56. package/src/types.ts +4 -1
  57. package/test/AutomergeUrl.test.ts +130 -0
  58. package/test/DocHandle.test.ts +209 -2
  59. package/test/DocSynchronizer.test.ts +10 -3
  60. package/test/Repo.test.ts +228 -3
  61. package/test/StorageSubsystem.test.ts +17 -0
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,6 +64,9 @@ export class DocHandle extends EventEmitter {
59
64
  this.emit("delete", { handle: this });
60
65
  return { doc: A.init() };
61
66
  }),
67
+ onUnload: assign(() => {
68
+ return { doc: A.init() };
69
+ }),
62
70
  onUnavailable: () => {
63
71
  this.emit("unavailable", { handle: this });
64
72
  },
@@ -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.#machine.send({ type: BEGIN });
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({ documentId: this.documentId });
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
  *
@@ -220,6 +245,13 @@ export class DocHandle extends EventEmitter {
220
245
  // if we timed out, return undefined
221
246
  return undefined;
222
247
  }
248
+ // If we have fixed heads, return a view at those heads
249
+ if (this.#fixedHeads) {
250
+ const doc = this.#doc;
251
+ if (!doc || this.isUnavailable())
252
+ return undefined;
253
+ return A.view(doc, decodeHeads(this.#fixedHeads));
254
+ }
223
255
  // Return the document
224
256
  return !this.isUnavailable() ? this.#doc : undefined;
225
257
  }
@@ -239,8 +271,11 @@ export class DocHandle extends EventEmitter {
239
271
  docSync() {
240
272
  if (!this.isReady())
241
273
  return undefined;
242
- else
243
- return this.#doc;
274
+ if (this.#fixedHeads) {
275
+ const doc = this.#doc;
276
+ return doc ? A.view(doc, decodeHeads(this.#fixedHeads)) : undefined;
277
+ }
278
+ return this.#doc;
244
279
  }
245
280
  /**
246
281
  * Returns the current "heads" of the document, akin to a git commit.
@@ -248,10 +283,120 @@ export class DocHandle extends EventEmitter {
248
283
  * @returns the current document's heads, or undefined if the document is not ready
249
284
  */
250
285
  heads() {
286
+ if (!this.isReady())
287
+ return undefined;
288
+ if (this.#fixedHeads) {
289
+ return this.#fixedHeads;
290
+ }
291
+ return encodeHeads(A.getHeads(this.#doc));
292
+ }
293
+ begin() {
294
+ this.#machine.send({ type: BEGIN });
295
+ }
296
+ /**
297
+ * Returns an array of all past "heads" for the document in topological order.
298
+ *
299
+ * @remarks
300
+ * A point-in-time in an automerge document is an *array* of heads since there may be
301
+ * concurrent edits. This API just returns a topologically sorted history of all edits
302
+ * so every previous entry will be (in some sense) before later ones, but the set of all possible
303
+ * history views would be quite large under concurrency (every thing in each branch against each other).
304
+ * There might be a clever way to think about this, but we haven't found it yet, so for now at least
305
+ * we present a single traversable view which excludes concurrency.
306
+ * @returns UrlHeads[] - The individual heads for every change in the document. Each item is a tagged string[1].
307
+ */
308
+ history() {
251
309
  if (!this.isReady()) {
252
310
  return undefined;
253
311
  }
254
- return A.getHeads(this.#doc);
312
+ // This just returns all the heads as individual strings.
313
+ return A.topoHistoryTraversal(this.#doc).map(h => encodeHeads([h]));
314
+ }
315
+ /**
316
+ * Creates a new DocHandle with a fixed "view" at the given point in time represented
317
+ * by the `heads` passed in. The return value is the same type as docSync() and will return
318
+ * undefined if the object hasn't finished loading.
319
+ *
320
+ * @remarks
321
+ * Note that our Typescript types do not consider change over time and the current version
322
+ * of Automerge doesn't check types at runtime, so if you go back to an old set of heads
323
+ * that doesn't match the heads here, Typescript will not save you.
324
+ *
325
+ * @argument heads - The heads to view the document at. See history().
326
+ * @returns DocHandle<T> at the time of `heads`
327
+ */
328
+ view(heads) {
329
+ if (!this.isReady()) {
330
+ throw new Error(`DocHandle#${this.documentId} is not ready. Check \`handle.isReady()\` before calling view().`);
331
+ }
332
+ // Create a new handle with the same documentId but fixed heads
333
+ const handle = new DocHandle(this.documentId, {
334
+ heads,
335
+ timeoutDelay: this.#timeoutDelay,
336
+ });
337
+ handle.update(() => A.clone(this.#doc));
338
+ handle.doneLoading();
339
+ return handle;
340
+ }
341
+ /**
342
+ * Returns a set of Patch operations that will move a materialized document from one state to another
343
+ * if applied.
344
+ *
345
+ * @remarks
346
+ * We allow specifying either:
347
+ * - Two sets of heads to compare directly
348
+ * - A single set of heads to compare against our current heads
349
+ * - Another DocHandle to compare against (which must share history with this document)
350
+ *
351
+ * @throws Error if the documents don't share history or if either document is not ready
352
+ * @returns Automerge patches that go from one document state to the other
353
+ */
354
+ diff(first, second) {
355
+ if (!this.isReady()) {
356
+ throw new Error(`DocHandle#${this.documentId} is not ready. Check \`handle.isReady()\` before calling diff().`);
357
+ }
358
+ const doc = this.#doc;
359
+ if (!doc)
360
+ throw new Error("Document not available");
361
+ // If first argument is a DocHandle
362
+ if (first instanceof DocHandle) {
363
+ if (!first.isReady()) {
364
+ throw new Error("Cannot diff against a handle that isn't ready");
365
+ }
366
+ const otherHeads = first.heads();
367
+ if (!otherHeads)
368
+ throw new Error("Other document's heads not available");
369
+ // Create a temporary merged doc to verify shared history and compute diff
370
+ const mergedDoc = A.merge(A.clone(doc), first.docSync());
371
+ // Use the merged doc to compute the diff
372
+ return A.diff(mergedDoc, decodeHeads(this.heads()), decodeHeads(otherHeads));
373
+ }
374
+ // Otherwise treat as heads
375
+ const from = second ? first : (this.heads() || []);
376
+ const to = second ? second : first;
377
+ return A.diff(doc, decodeHeads(from), decodeHeads(to));
378
+ }
379
+ /**
380
+ * `metadata(head?)` allows you to look at the metadata for a change
381
+ * this can be used to build history graphs to find commit messages and edit times.
382
+ * this interface.
383
+ *
384
+ * @remarks
385
+ * I'm really not convinced this is the right way to surface this information so
386
+ * I'm leaving this API "hidden".
387
+ *
388
+ * @hidden
389
+ */
390
+ metadata(change) {
391
+ if (!this.isReady()) {
392
+ return undefined;
393
+ }
394
+ if (!change) {
395
+ change = this.heads()[0];
396
+ }
397
+ // we return undefined instead of null by convention in this API
398
+ return (A.inspectChange(this.#doc, decodeHeads([change])[0]) ||
399
+ undefined);
255
400
  }
256
401
  /**
257
402
  * `update` is called any time we have a new document state; could be
@@ -301,6 +446,9 @@ export class DocHandle extends EventEmitter {
301
446
  if (!this.isReady()) {
302
447
  throw new Error(`DocHandle#${this.documentId} is in ${this.state} and not ready. Check \`handle.isReady()\` before accessing the document.`);
303
448
  }
449
+ if (this.#fixedHeads) {
450
+ throw new Error(`DocHandle#${this.documentId} is in view-only mode at specific heads. Use clone() to create a new document from this state.`);
451
+ }
304
452
  this.#machine.send({
305
453
  type: UPDATE,
306
454
  payload: { callback: doc => A.change(doc, options, callback) },
@@ -315,13 +463,18 @@ export class DocHandle extends EventEmitter {
315
463
  if (!this.isReady()) {
316
464
  throw new Error(`DocHandle#${this.documentId} is not ready. Check \`handle.isReady()\` before accessing the document.`);
317
465
  }
466
+ if (this.#fixedHeads) {
467
+ throw new Error(`DocHandle#${this.documentId} is in view-only mode at specific heads. Use clone() to create a new document from this state.`);
468
+ }
318
469
  let resultHeads = undefined;
319
470
  this.#machine.send({
320
471
  type: UPDATE,
321
472
  payload: {
322
473
  callback: doc => {
323
- const result = A.changeAt(doc, heads, options, callback);
324
- resultHeads = result.newHeads || undefined;
474
+ const result = A.changeAt(doc, decodeHeads(heads), options, callback);
475
+ resultHeads = result.newHeads
476
+ ? encodeHeads(result.newHeads)
477
+ : undefined;
325
478
  return result.newDoc;
326
479
  },
327
480
  },
@@ -343,6 +496,9 @@ export class DocHandle extends EventEmitter {
343
496
  if (!this.isReady() || !otherHandle.isReady()) {
344
497
  throw new Error("Both handles must be ready to merge");
345
498
  }
499
+ if (this.#fixedHeads) {
500
+ throw new Error(`DocHandle#${this.documentId} is in view-only mode at specific heads. Use clone() to create a new document from this state.`);
501
+ }
346
502
  const mergingDoc = otherHandle.docSync();
347
503
  if (!mergingDoc) {
348
504
  throw new Error("The document to be merged in is falsy, aborting.");
@@ -365,6 +521,14 @@ export class DocHandle extends EventEmitter {
365
521
  if (this.#state === "loading")
366
522
  this.#machine.send({ type: REQUEST });
367
523
  }
524
+ /** Called by the repo to free memory used by the document. */
525
+ unload() {
526
+ this.#machine.send({ type: UNLOAD });
527
+ }
528
+ /** Called by the repo to reuse an unloaded handle. */
529
+ reload() {
530
+ this.#machine.send({ type: RELOAD });
531
+ }
368
532
  /** Called by the repo when the document is deleted. */
369
533
  delete() {
370
534
  this.#machine.send({ type: DELETE });
@@ -382,6 +546,9 @@ export class DocHandle extends EventEmitter {
382
546
  data: encode(message),
383
547
  });
384
548
  }
549
+ metrics() {
550
+ return A.stats(this.#doc);
551
+ }
385
552
  }
386
553
  // STATE MACHINE TYPES & CONSTANTS
387
554
  // state
@@ -397,16 +564,20 @@ export const HandleState = {
397
564
  REQUESTING: "requesting",
398
565
  /** The document is available */
399
566
  READY: "ready",
567
+ /** The document has been unloaded from the handle, to free memory usage */
568
+ UNLOADED: "unloaded",
400
569
  /** The document has been deleted from the repo */
401
570
  DELETED: "deleted",
402
571
  /** The document was not available in storage or from any connected peers */
403
572
  UNAVAILABLE: "unavailable",
404
573
  };
405
- export const { IDLE, LOADING, REQUESTING, READY, DELETED, UNAVAILABLE } = HandleState;
574
+ export const { IDLE, LOADING, REQUESTING, READY, UNLOADED, DELETED, UNAVAILABLE, } = HandleState;
406
575
  const BEGIN = "BEGIN";
407
576
  const REQUEST = "REQUEST";
408
577
  const DOC_READY = "DOC_READY";
409
578
  const UPDATE = "UPDATE";
579
+ const UNLOAD = "UNLOAD";
580
+ const RELOAD = "RELOAD";
410
581
  const DELETE = "DELETE";
411
582
  const TIMEOUT = "TIMEOUT";
412
583
  const DOC_UNAVAILABLE = "DOC_UNAVAILABLE";
@@ -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: A.Heads;
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: A.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: A.Heads): void;
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,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAC/C,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,CAAC,CAAC,KAAK,CAAA;IACpB,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,CAAC,CAAC,KAAK,CAAA;IACd,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,CAAC,CAAC,KAAK;IAgChB,eAAe,CAAC,MAAM,EAAE,MAAM;IAwB9B,UAAU,CAAC,MAAM,EAAE,MAAM;IA2BzB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;CAoE1D"}
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, { timestamp, heads });
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,9 @@ 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 type { AnyDocumentId, DocumentId, PeerId } from "./types.js";
8
+ import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
9
+ import { DocSyncMetrics } from "./synchronizer/Synchronizer.js";
10
+ import type { AnyDocumentId, AutomergeUrl, DocumentId, PeerId } from "./types.js";
9
11
  /** A Repo is a collection of documents with networking, syncing, and storage capabilities. */
10
12
  /** The `Repo` is the main entry point of this library
11
13
  *
@@ -23,13 +25,15 @@ export declare class Repo extends EventEmitter<RepoEvents> {
23
25
  /** The debounce rate is adjustable on the repo. */
24
26
  /** @hidden */
25
27
  saveDebounceRate: number;
28
+ /** @hidden */
29
+ synchronizer: CollectionSynchronizer;
26
30
  /** By default, we share generously with all peers. */
27
31
  /** @hidden */
28
32
  sharePolicy: SharePolicy;
29
33
  /** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
30
34
  /** @hidden */
31
35
  peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
32
- constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, }?: RepoConfig);
36
+ constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, denylist, }?: RepoConfig);
33
37
  /** Returns all the handles we have cached. */
34
38
  get handles(): Record<DocumentId, DocHandle<any>>;
35
39
  /** Returns a list of all connected peer ids */
@@ -89,7 +93,19 @@ export declare class Repo extends EventEmitter<RepoEvents> {
89
93
  * @returns Promise<void>
90
94
  */
91
95
  flush(documents?: DocumentId[]): Promise<void>;
96
+ /**
97
+ * Removes a DocHandle from the handleCache.
98
+ * @hidden this API is experimental and may change.
99
+ * @param documentId - documentId of the DocHandle to remove from handleCache, if present in cache.
100
+ * @returns Promise<void>
101
+ */
102
+ removeFromCache(documentId: DocumentId): Promise<void>;
92
103
  shutdown(): Promise<void>;
104
+ metrics(): {
105
+ documents: {
106
+ [key: string]: any;
107
+ };
108
+ };
93
109
  }
94
110
  export interface RepoConfig {
95
111
  /** Our unique identifier */
@@ -110,6 +126,12 @@ export interface RepoConfig {
110
126
  * Whether to enable the experimental remote heads gossiping feature
111
127
  */
112
128
  enableRemoteHeadsGossiping?: boolean;
129
+ /**
130
+ * A list of automerge URLs which should never be loaded regardless of what
131
+ * messages are received or what the share policy is. This is useful to avoid
132
+ * loading documents that are known to be too resource intensive.
133
+ */
134
+ denylist?: AutomergeUrl[];
113
135
  }
114
136
  /** A function that determines whether we should share a document with a peer
115
137
  *
@@ -127,6 +149,7 @@ export interface RepoEvents {
127
149
  "delete-document": (arg: DeleteDocumentPayload) => void;
128
150
  /** A document was marked as unavailable (we don't have it and none of our peers have it) */
129
151
  "unavailable-document": (arg: DeleteDocumentPayload) => void;
152
+ "doc-metrics": (arg: DocMetrics) => void;
130
153
  }
131
154
  export interface DocumentPayload {
132
155
  handle: DocHandle<any>;
@@ -134,4 +157,14 @@ export interface DocumentPayload {
134
157
  export interface DeleteDocumentPayload {
135
158
  documentId: DocumentId;
136
159
  }
160
+ export type DocMetrics = DocSyncMetrics | {
161
+ type: "doc-loaded";
162
+ documentId: DocumentId;
163
+ durationMillis: number;
164
+ numOps: number;
165
+ numChanges: number;
166
+ } | {
167
+ type: "doc-denied";
168
+ documentId: DocumentId;
169
+ };
137
170
  //# sourceMappingURL=Repo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAQ5C,OAAO,EAEL,SAAS,EAKV,MAAM,gBAAgB,CAAA;AAIvB,OAAO,EACL,uBAAuB,EACvB,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAA;AACjF,OAAO,EACL,cAAc,EAEf,MAAM,gCAAgC,CAAA;AACvC,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,MAAM,EACP,MAAM,YAAY,CAAA;AAMnB,8FAA8F;AAC9F;;;;;;GAMG;AACH,qBAAa,IAAK,SAAQ,YAAY,CAAC,UAAU,CAAC;;IAGhD,cAAc;IACd,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,cAAc;IACd,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC,mDAAmD;IACnD,cAAc;IACd,gBAAgB,SAAM;IAItB,cAAc;IACd,YAAY,EAAE,sBAAsB,CAAA;IAEpC,sDAAsD;IACtD,cAAc;IACd,WAAW,EAAE,WAAW,CAAmB;IAE3C,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAK3C,EACV,OAAO,EACP,OAAY,EACZ,MAAuB,EACvB,WAAW,EACX,WAAmC,EACnC,0BAAkC,EAClC,QAAa,GACd,GAAE,UAAe;IAoQlB,8CAA8C;IAC9C,IAAI,OAAO,uCAEV;IAED,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIzD;;;;OAIG;IACH,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAuBzC;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAuBnC;;;OAGG;IACH,IAAI,CAAC,CAAC;IACJ,sDAAsD;IACtD,EAAE,EAAE,aAAa,GAChB,SAAS,CAAC,CAAC,CAAC;IAoDf,MAAM;IACJ,oDAAoD;IACpD,EAAE,EAAE,aAAa;IAWnB;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAShE;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU;IAY5B,kBAAkB,YAAa,SAAS,EAAE,UASzC;IAED,SAAS,QAAa,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAMnD;IAED;;;;;OAKG;IACG,KAAK,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBpD;;;;;OAKG;IACG,eAAe,CAAC,UAAU,EAAE,UAAU;IA2B5C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,OAAO,IAAI;QAAE,SAAS,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAA;KAAE;CAGjD;AAED,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;8DAC0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB,gDAAgD;IAChD,OAAO,CAAC,EAAE,uBAAuB,CAAA;IAEjC,iEAAiE;IACjE,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAA;IAEnC;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IAEzB;;OAEG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAA;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAA;CAC1B;AAED;;;;;;;KAOK;AACL,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,KACpB,OAAO,CAAC,OAAO,CAAC,CAAA;AAGrB,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;IACxC,6BAA6B;IAC7B,iBAAiB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IACvD,4FAA4F;IAC5F,sBAAsB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IAC5D,aAAa,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAA;CACzC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,MAAM,MAAM,UAAU,GAClB,cAAc,GACd;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GACD;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA"}