@automerge/automerge-repo 2.4.0 → 2.5.0-alpha.0
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/dist/DocHandle.d.ts +8 -3
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +20 -7
- package/dist/Repo.d.ts +9 -0
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +2 -0
- package/dist/helpers/abortable.d.ts +7 -0
- package/dist/helpers/abortable.d.ts.map +1 -1
- package/dist/helpers/abortable.js +13 -0
- package/dist/storage/StorageSubsystem.d.ts +9 -0
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +13 -1
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +7 -0
- package/dist/synchronizer/Synchronizer.d.ts +4 -0
- package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/DocHandle.ts +33 -7
- package/src/Repo.ts +17 -0
- package/src/helpers/abortable.ts +16 -0
- package/src/storage/StorageSubsystem.ts +24 -1
- package/src/synchronizer/DocSynchronizer.ts +8 -0
- package/src/synchronizer/Synchronizer.ts +5 -0
- package/test/Repo.test.ts +169 -4
package/dist/DocHandle.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { next as A } from "@automerge/automerge/slim";
|
|
|
2
2
|
import { EventEmitter } from "eventemitter3";
|
|
3
3
|
import type { AutomergeUrl, DocumentId, PeerId, UrlHeads } from "./types.js";
|
|
4
4
|
import { StorageId } from "./storage/types.js";
|
|
5
|
+
import { AbortOptions } from "./helpers/abortable.js";
|
|
5
6
|
/**
|
|
6
7
|
* A DocHandle is a wrapper around a single Automerge document that lets us listen for changes and
|
|
7
8
|
* notify the network and storage of new changes.
|
|
@@ -57,13 +58,17 @@ export declare class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
|
|
|
57
58
|
/** @hidden */
|
|
58
59
|
get state(): "idle" | "loading" | "requesting" | "ready" | "unavailable" | "unloaded" | "deleted";
|
|
59
60
|
/**
|
|
60
|
-
*
|
|
61
|
-
* are passed, when the document is ready)
|
|
61
|
+
* Returns promise that resolves when document is in one of the given states (default is 'ready' state)
|
|
62
62
|
*
|
|
63
63
|
* Use this to block until the document handle has finished loading. The async equivalent to
|
|
64
64
|
* checking `inState()`.
|
|
65
|
+
*
|
|
66
|
+
* @param awaitStates - HandleState or HandleStates to wait for
|
|
67
|
+
* @param signal - Optional AbortSignal to cancel the waiting operation
|
|
68
|
+
* @returns a promise that resolves when the document is in one of the given states (if no states
|
|
69
|
+
* are passed, when the document is ready)
|
|
65
70
|
*/
|
|
66
|
-
whenReady(awaitStates?: HandleState[]): Promise<void>;
|
|
71
|
+
whenReady(awaitStates?: HandleState[], options?: AbortOptions): Promise<void>;
|
|
67
72
|
/**
|
|
68
73
|
* Returns the current state of the Automerge document this handle manages.
|
|
69
74
|
*
|
package/dist/DocHandle.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAU5C,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"DocHandle.d.ts","sourceRoot":"","sources":["../src/DocHandle.ts"],"names":[],"mappings":"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"}
|
package/dist/DocHandle.js
CHANGED
|
@@ -6,6 +6,7 @@ import { decodeHeads, encodeHeads, stringifyAutomergeUrl, } from "./AutomergeUrl
|
|
|
6
6
|
import { encode } from "./helpers/cbor.js";
|
|
7
7
|
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
8
8
|
import { withTimeout } from "./helpers/withTimeout.js";
|
|
9
|
+
import { AbortError, isAbortErrorLike, } from "./helpers/abortable.js";
|
|
9
10
|
/**
|
|
10
11
|
* A DocHandle is a wrapper around a single Automerge document that lets us listen for changes and
|
|
11
12
|
* notify the network and storage of new changes.
|
|
@@ -141,14 +142,19 @@ export class DocHandle extends EventEmitter {
|
|
|
141
142
|
get #state() {
|
|
142
143
|
return this.#machine?.getSnapshot().value;
|
|
143
144
|
}
|
|
144
|
-
/**
|
|
145
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Returns a promise that resolves when the docHandle is in one of the given states
|
|
147
|
+
*
|
|
148
|
+
* @param awaitStates - HandleState or HandleStates to wait for
|
|
149
|
+
* @param signal - Optional AbortSignal to cancel the waiting operation
|
|
150
|
+
*/
|
|
151
|
+
#statePromise(awaitStates, options) {
|
|
146
152
|
const awaitStatesArray = Array.isArray(awaitStates)
|
|
147
153
|
? awaitStates
|
|
148
154
|
: [awaitStates];
|
|
149
155
|
return waitFor(this.#machine, s => awaitStatesArray.some(state => s.matches(state)),
|
|
150
156
|
// use a longer delay here so as not to race with other delays
|
|
151
|
-
{ timeout: this.#timeoutDelay * 2 });
|
|
157
|
+
{ timeout: this.#timeoutDelay * 2, ...options });
|
|
152
158
|
}
|
|
153
159
|
/**
|
|
154
160
|
* Update the document with whatever the result of callback is
|
|
@@ -254,17 +260,24 @@ export class DocHandle extends EventEmitter {
|
|
|
254
260
|
return this.#machine.getSnapshot().value;
|
|
255
261
|
}
|
|
256
262
|
/**
|
|
257
|
-
*
|
|
258
|
-
* are passed, when the document is ready)
|
|
263
|
+
* Returns promise that resolves when document is in one of the given states (default is 'ready' state)
|
|
259
264
|
*
|
|
260
265
|
* Use this to block until the document handle has finished loading. The async equivalent to
|
|
261
266
|
* checking `inState()`.
|
|
267
|
+
*
|
|
268
|
+
* @param awaitStates - HandleState or HandleStates to wait for
|
|
269
|
+
* @param signal - Optional AbortSignal to cancel the waiting operation
|
|
270
|
+
* @returns a promise that resolves when the document is in one of the given states (if no states
|
|
271
|
+
* are passed, when the document is ready)
|
|
262
272
|
*/
|
|
263
|
-
async whenReady(awaitStates = ["ready"]) {
|
|
273
|
+
async whenReady(awaitStates = ["ready"], options) {
|
|
264
274
|
try {
|
|
265
|
-
await withTimeout(this.#statePromise(awaitStates), this.#timeoutDelay);
|
|
275
|
+
await withTimeout(this.#statePromise(awaitStates, options), this.#timeoutDelay);
|
|
266
276
|
}
|
|
267
277
|
catch (error) {
|
|
278
|
+
if (isAbortErrorLike(error)) {
|
|
279
|
+
throw new AbortError(); //throw new error for stack trace
|
|
280
|
+
}
|
|
268
281
|
console.log(`error waiting for ${this.documentId} to be in one of states: ${awaitStates.join(", ")}`);
|
|
269
282
|
throw error;
|
|
270
283
|
}
|
package/dist/Repo.d.ts
CHANGED
|
@@ -241,6 +241,15 @@ export interface DeleteDocumentPayload {
|
|
|
241
241
|
documentId: DocumentId;
|
|
242
242
|
}
|
|
243
243
|
export type DocMetrics = DocSyncMetrics | {
|
|
244
|
+
type: "doc-compacted";
|
|
245
|
+
documentId: DocumentId;
|
|
246
|
+
durationMillis: number;
|
|
247
|
+
} | {
|
|
248
|
+
type: "doc-saved";
|
|
249
|
+
documentId: DocumentId;
|
|
250
|
+
durationMillis: number;
|
|
251
|
+
sinceHeads: Array<string>;
|
|
252
|
+
} | {
|
|
244
253
|
type: "doc-loaded";
|
|
245
254
|
documentId: DocumentId;
|
|
246
255
|
durationMillis: number;
|
package/dist/Repo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,EAAE,MAAM,2BAA2B,CAAA;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAS5C,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,EAEZ,UAAU,EACV,MAAM,EACP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAa,YAAY,EAAc,MAAM,wBAAwB,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG;IACzD,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;IAChE,IAAI,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IAC3B,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;CACzE,CAAA;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IAC3B,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;IACxE,UAAU,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;CACjE,CAAA;AAMD,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;IAUnC,cAAc;IACd,YAAY,EAAE,sBAAsB,CAAA;IAOpC,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAW3C,EACV,OAAO,EACP,OAAY,EACZ,MAAuB,EACvB,WAAW,EACX,WAAW,EACX,WAAmC,EACnC,0BAAkC,EAClC,QAAa,EACb,gBAAsB,EACtB,SAAS,GACV,GAAE,UAAe;
|
|
1
|
+
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
|
package/dist/Repo.js
CHANGED
|
@@ -92,6 +92,8 @@ export class Repo extends EventEmitter {
|
|
|
92
92
|
const storageSubsystem = storage ? new StorageSubsystem(storage) : undefined;
|
|
93
93
|
if (storageSubsystem) {
|
|
94
94
|
storageSubsystem.on("document-loaded", event => this.emit("doc-metrics", { type: "doc-loaded", ...event }));
|
|
95
|
+
storageSubsystem.on("doc-compacted", event => this.emit("doc-metrics", { type: "doc-compacted", ...event }));
|
|
96
|
+
storageSubsystem.on("doc-saved", event => this.emit("doc-metrics", { type: "doc-saved", ...event }));
|
|
95
97
|
}
|
|
96
98
|
this.storageSubsystem = storageSubsystem;
|
|
97
99
|
this.#saveDebounceRate = saveDebounceRate;
|
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
export declare class AbortError extends DOMException {
|
|
14
14
|
constructor(message?: string);
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Detects if candidate `Error` is an `AbortError` or AbortError-like.
|
|
18
|
+
* @remarks
|
|
19
|
+
* - This method detects if an error is AbortError-like (for which there could be many implementations)
|
|
20
|
+
* - AbortController spec defines AbortError as DOMException or Error with `name === 'AbortError'`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const isAbortErrorLike: (candidate: unknown) => boolean;
|
|
16
23
|
/**
|
|
17
24
|
* Wraps a Promise and causes it to reject when the signal is aborted.
|
|
18
25
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"abortable.d.ts","sourceRoot":"","sources":["../../src/helpers/abortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,qBAAa,UAAW,SAAQ,YAAY;gBAC9B,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB"}
|
|
1
|
+
{"version":3,"file":"abortable.d.ts","sourceRoot":"","sources":["../../src/helpers/abortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,qBAAa,UAAW,SAAQ,YAAY;gBAC9B,OAAO,CAAC,EAAE,MAAM;CAG7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,WAAW,OAAO,KAAG,OAQrD,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACzB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB"}
|
|
@@ -15,6 +15,19 @@ export class AbortError extends DOMException {
|
|
|
15
15
|
super(message ?? "Operation aborted", "AbortError");
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Detects if candidate `Error` is an `AbortError` or AbortError-like.
|
|
20
|
+
* @remarks
|
|
21
|
+
* - This method detects if an error is AbortError-like (for which there could be many implementations)
|
|
22
|
+
* - AbortController spec defines AbortError as DOMException or Error with `name === 'AbortError'`.
|
|
23
|
+
*/
|
|
24
|
+
export const isAbortErrorLike = (candidate) => {
|
|
25
|
+
return (candidate instanceof AbortError ||
|
|
26
|
+
((candidate instanceof Error ||
|
|
27
|
+
//In some JS environments, DOMException is not defined, and sometimes when defined, it does not extend Error; hence extra checks
|
|
28
|
+
(DOMException && candidate instanceof DOMException)) &&
|
|
29
|
+
candidate.name === "AbortError"));
|
|
30
|
+
};
|
|
18
31
|
/**
|
|
19
32
|
* Wraps a Promise and causes it to reject when the signal is aborted.
|
|
20
33
|
*
|
|
@@ -10,6 +10,15 @@ type StorageSubsystemEvents = {
|
|
|
10
10
|
numOps: number;
|
|
11
11
|
numChanges: number;
|
|
12
12
|
}) => void;
|
|
13
|
+
"doc-compacted": (arg: {
|
|
14
|
+
documentId: DocumentId;
|
|
15
|
+
durationMillis: number;
|
|
16
|
+
}) => void;
|
|
17
|
+
"doc-saved": (arg: {
|
|
18
|
+
documentId: DocumentId;
|
|
19
|
+
durationMillis: number;
|
|
20
|
+
sinceHeads: A.Heads;
|
|
21
|
+
}) => void;
|
|
13
22
|
};
|
|
14
23
|
/**
|
|
15
24
|
* The storage subsystem is responsible for saving and loading Automerge documents to and from
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAIrD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAG5C,KAAK,sBAAsB,GAAG;IAC5B,iBAAiB,EAAE,CAAC,GAAG,EAAE;QACvB,UAAU,EAAE,UAAU,CAAA;QACtB,cAAc,EAAE,MAAM,CAAA;QACtB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;KACnB,KAAK,IAAI,CAAA;CACX,CAAA;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;gBAe5D,cAAc,EAAE,uBAAuB;IAK7C,EAAE,IAAI,OAAO,CAAC,SAAS,CAAC;IA2B9B,kCAAkC;IAC5B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKlC,gCAAgC;IAC1B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM;IAEX,sCAAsC;IACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC;IAKhB,oCAAoC;IAC9B,MAAM;IACV,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,2FAA2F;IAC3F,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAgDrE;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAqBlE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAezE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;
|
|
1
|
+
{"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAIrD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAG7D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAG5C,KAAK,sBAAsB,GAAG;IAC5B,iBAAiB,EAAE,CAAC,GAAG,EAAE;QACvB,UAAU,EAAE,UAAU,CAAA;QACtB,cAAc,EAAE,MAAM,CAAA;QACtB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;KACnB,KAAK,IAAI,CAAA;IACV,eAAe,EAAE,CAAC,GAAG,EAAE;QACrB,UAAU,EAAE,UAAU,CAAA;QACtB,cAAc,EAAE,MAAM,CAAA;KACvB,KAAK,IAAI,CAAA;IACV,WAAW,EAAE,CAAC,GAAG,EAAE;QACjB,UAAU,EAAE,UAAU,CAAA;QACtB,cAAc,EAAE,MAAM,CAAA;QACtB,UAAU,EAAE,CAAC,CAAC,KAAK,CAAA;KACpB,KAAK,IAAI,CAAA;CACX,CAAA;AAED;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;gBAe5D,cAAc,EAAE,uBAAuB;IAK7C,EAAE,IAAI,OAAO,CAAC,SAAS,CAAC;IA2B9B,kCAAkC;IAC5B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKlC,gCAAgC;IAC1B,IAAI;IACR,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,yFAAyF;IACzF,GAAG,EAAE,MAAM;IAEX,sCAAsC;IACtC,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC;IAKhB,oCAAoC;IAC9B,MAAM;IACV,iFAAiF;IACjF,SAAS,EAAE,MAAM;IAEjB,2FAA2F;IAC3F,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC;IAOhB;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAgDrE;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAqBlE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAezE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAgFhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAW7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;CA8CjB"}
|
|
@@ -173,7 +173,16 @@ export class StorageSubsystem extends EventEmitter {
|
|
|
173
173
|
* Saves just the incremental changes since the last save.
|
|
174
174
|
*/
|
|
175
175
|
async #saveIncremental(documentId, doc) {
|
|
176
|
-
const
|
|
176
|
+
const sinceHeads = this.#storedHeads.get(documentId) ?? [];
|
|
177
|
+
const start = performance.now();
|
|
178
|
+
const binary = A.saveSince(doc, sinceHeads);
|
|
179
|
+
const end = performance.now();
|
|
180
|
+
console.log("emitting saved");
|
|
181
|
+
this.emit("doc-saved", {
|
|
182
|
+
documentId,
|
|
183
|
+
durationMillis: end - start,
|
|
184
|
+
sinceHeads,
|
|
185
|
+
});
|
|
177
186
|
if (binary && binary.length > 0) {
|
|
178
187
|
const key = [documentId, "incremental", keyHash(binary)];
|
|
179
188
|
this.#log(`Saving incremental ${key} for document ${documentId}`);
|
|
@@ -197,7 +206,10 @@ export class StorageSubsystem extends EventEmitter {
|
|
|
197
206
|
*/
|
|
198
207
|
async #saveTotal(documentId, doc, sourceChunks) {
|
|
199
208
|
this.#compacting = true;
|
|
209
|
+
const start = performance.now();
|
|
200
210
|
const binary = A.save(doc);
|
|
211
|
+
const end = performance.now();
|
|
212
|
+
this.emit("doc-compacted", { documentId, durationMillis: end - start });
|
|
201
213
|
const snapshotHash = headsHash(A.getHeads(doc));
|
|
202
214
|
const key = [documentId, "snapshot", snapshotHash];
|
|
203
215
|
const oldKeys = new Set(sourceChunks.map(c => c.key).filter(k => k[2] !== snapshotHash));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAGrD,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,WAAW,EAEZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;CACvE;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAyBV,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyBtE,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;
|
|
1
|
+
{"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,2BAA2B,CAAA;AAGrD,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,WAAW,EAEZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;CACvE;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAyBV,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyBtE,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IA6ID,OAAO,CAAC,MAAM,EAAE,MAAM;IAIhB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA8DjC,OAAO,CAAC,MAAM,EAAE,MAAM;IAOtB,cAAc,CAAC,OAAO,EAAE,WAAW;IAkBnC,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;IAuBjD,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;IA2FxD,OAAO,IAAI;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE;CAM7E"}
|
|
@@ -121,7 +121,14 @@ export class DocSynchronizer extends Synchronizer {
|
|
|
121
121
|
#sendSyncMessage(peerId, doc) {
|
|
122
122
|
this.#log(`sendSyncMessage ->${peerId}`);
|
|
123
123
|
this.#withSyncState(peerId, syncState => {
|
|
124
|
+
const start = performance.now();
|
|
124
125
|
const [newSyncState, message] = A.generateSyncMessage(doc, syncState);
|
|
126
|
+
const end = performance.now();
|
|
127
|
+
this.emit("metrics", {
|
|
128
|
+
type: "generate-sync-message",
|
|
129
|
+
documentId: this.#handle.documentId,
|
|
130
|
+
durationMillis: end - start,
|
|
131
|
+
});
|
|
125
132
|
if (message) {
|
|
126
133
|
this.#setSyncState(peerId, newSyncState);
|
|
127
134
|
const isNew = A.getHeads(doc).length === 0;
|
|
@@ -23,6 +23,10 @@ export type DocSyncMetrics = {
|
|
|
23
23
|
durationMillis: number;
|
|
24
24
|
numOps: number;
|
|
25
25
|
numChanges: number;
|
|
26
|
+
} | {
|
|
27
|
+
type: "generate-sync-message";
|
|
28
|
+
documentId: DocumentId;
|
|
29
|
+
durationMillis: number;
|
|
26
30
|
} | {
|
|
27
31
|
type: "doc-denied";
|
|
28
32
|
documentId: DocumentId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/Synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhD,8BAAsB,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACjD,UAAU,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;IACzC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;CACvC;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,sBAAsB,CAAA;IAC5B,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"}
|
|
1
|
+
{"version":3,"file":"Synchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/Synchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EACL,eAAe,EACf,cAAc,EACd,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhD,8BAAsB,YAAa,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IACzE,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;CACpD;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACjD,UAAU,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;IACzC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAA;CACvC;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,sBAAsB,CAAA;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB,GACD;IACE,IAAI,EAAE,uBAAuB,CAAA;IAC7B,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;CACvB,GACD;IACE,IAAI,EAAE,YAAY,CAAA;IAClB,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0-alpha.0",
|
|
4
4
|
"description": "A repository object to manage a collection of automerge documents",
|
|
5
5
|
"repository": "https://github.com/automerge/automerge-repo/tree/master/packages/automerge-repo",
|
|
6
6
|
"author": "Peter van Hardenberg <pvh@pvh.ca>",
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "6d94459eecf708f9c508be7e22c2035abffc03a4"
|
|
63
63
|
}
|
package/src/DocHandle.ts
CHANGED
|
@@ -12,6 +12,11 @@ import { headsAreSame } from "./helpers/headsAreSame.js"
|
|
|
12
12
|
import { withTimeout } from "./helpers/withTimeout.js"
|
|
13
13
|
import type { AutomergeUrl, DocumentId, PeerId, UrlHeads } from "./types.js"
|
|
14
14
|
import { StorageId } from "./storage/types.js"
|
|
15
|
+
import {
|
|
16
|
+
AbortError,
|
|
17
|
+
AbortOptions,
|
|
18
|
+
isAbortErrorLike,
|
|
19
|
+
} from "./helpers/abortable.js"
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* A DocHandle is a wrapper around a single Automerge document that lets us listen for changes and
|
|
@@ -170,8 +175,16 @@ export class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
|
|
|
170
175
|
return this.#machine?.getSnapshot().value
|
|
171
176
|
}
|
|
172
177
|
|
|
173
|
-
/**
|
|
174
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Returns a promise that resolves when the docHandle is in one of the given states
|
|
180
|
+
*
|
|
181
|
+
* @param awaitStates - HandleState or HandleStates to wait for
|
|
182
|
+
* @param signal - Optional AbortSignal to cancel the waiting operation
|
|
183
|
+
*/
|
|
184
|
+
#statePromise(
|
|
185
|
+
awaitStates: HandleState | HandleState[],
|
|
186
|
+
options?: AbortOptions
|
|
187
|
+
) {
|
|
175
188
|
const awaitStatesArray = Array.isArray(awaitStates)
|
|
176
189
|
? awaitStates
|
|
177
190
|
: [awaitStates]
|
|
@@ -179,7 +192,7 @@ export class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
|
|
|
179
192
|
this.#machine,
|
|
180
193
|
s => awaitStatesArray.some(state => s.matches(state)),
|
|
181
194
|
// use a longer delay here so as not to race with other delays
|
|
182
|
-
{ timeout: this.#timeoutDelay * 2 }
|
|
195
|
+
{ timeout: this.#timeoutDelay * 2, ...options }
|
|
183
196
|
)
|
|
184
197
|
}
|
|
185
198
|
|
|
@@ -301,16 +314,29 @@ export class DocHandle<T> extends EventEmitter<DocHandleEvents<T>> {
|
|
|
301
314
|
}
|
|
302
315
|
|
|
303
316
|
/**
|
|
304
|
-
*
|
|
305
|
-
* are passed, when the document is ready)
|
|
317
|
+
* Returns promise that resolves when document is in one of the given states (default is 'ready' state)
|
|
306
318
|
*
|
|
307
319
|
* Use this to block until the document handle has finished loading. The async equivalent to
|
|
308
320
|
* checking `inState()`.
|
|
321
|
+
*
|
|
322
|
+
* @param awaitStates - HandleState or HandleStates to wait for
|
|
323
|
+
* @param signal - Optional AbortSignal to cancel the waiting operation
|
|
324
|
+
* @returns a promise that resolves when the document is in one of the given states (if no states
|
|
325
|
+
* are passed, when the document is ready)
|
|
309
326
|
*/
|
|
310
|
-
async whenReady(
|
|
327
|
+
async whenReady(
|
|
328
|
+
awaitStates: HandleState[] = ["ready"],
|
|
329
|
+
options?: AbortOptions
|
|
330
|
+
) {
|
|
311
331
|
try {
|
|
312
|
-
await withTimeout(
|
|
332
|
+
await withTimeout(
|
|
333
|
+
this.#statePromise(awaitStates, options),
|
|
334
|
+
this.#timeoutDelay
|
|
335
|
+
)
|
|
313
336
|
} catch (error) {
|
|
337
|
+
if (isAbortErrorLike(error)) {
|
|
338
|
+
throw new AbortError() //throw new error for stack trace
|
|
339
|
+
}
|
|
314
340
|
console.log(
|
|
315
341
|
`error waiting for ${
|
|
316
342
|
this.documentId
|
package/src/Repo.ts
CHANGED
|
@@ -172,6 +172,12 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
172
172
|
storageSubsystem.on("document-loaded", event =>
|
|
173
173
|
this.emit("doc-metrics", { type: "doc-loaded", ...event })
|
|
174
174
|
)
|
|
175
|
+
storageSubsystem.on("doc-compacted", event =>
|
|
176
|
+
this.emit("doc-metrics", { type: "doc-compacted", ...event })
|
|
177
|
+
)
|
|
178
|
+
storageSubsystem.on("doc-saved", event =>
|
|
179
|
+
this.emit("doc-metrics", { type: "doc-saved", ...event })
|
|
180
|
+
)
|
|
175
181
|
}
|
|
176
182
|
|
|
177
183
|
this.storageSubsystem = storageSubsystem
|
|
@@ -1088,6 +1094,17 @@ export interface DeleteDocumentPayload {
|
|
|
1088
1094
|
|
|
1089
1095
|
export type DocMetrics =
|
|
1090
1096
|
| DocSyncMetrics
|
|
1097
|
+
| {
|
|
1098
|
+
type: "doc-compacted"
|
|
1099
|
+
documentId: DocumentId
|
|
1100
|
+
durationMillis: number
|
|
1101
|
+
}
|
|
1102
|
+
| {
|
|
1103
|
+
type: "doc-saved"
|
|
1104
|
+
documentId: DocumentId
|
|
1105
|
+
durationMillis: number
|
|
1106
|
+
sinceHeads: Array<string>
|
|
1107
|
+
}
|
|
1091
1108
|
| {
|
|
1092
1109
|
type: "doc-loaded"
|
|
1093
1110
|
documentId: DocumentId
|
package/src/helpers/abortable.ts
CHANGED
|
@@ -16,6 +16,22 @@ export class AbortError extends DOMException {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Detects if candidate `Error` is an `AbortError` or AbortError-like.
|
|
21
|
+
* @remarks
|
|
22
|
+
* - This method detects if an error is AbortError-like (for which there could be many implementations)
|
|
23
|
+
* - AbortController spec defines AbortError as DOMException or Error with `name === 'AbortError'`.
|
|
24
|
+
*/
|
|
25
|
+
export const isAbortErrorLike = (candidate: unknown): boolean => {
|
|
26
|
+
return (
|
|
27
|
+
candidate instanceof AbortError ||
|
|
28
|
+
((candidate instanceof Error ||
|
|
29
|
+
//In some JS environments, DOMException is not defined, and sometimes when defined, it does not extend Error; hence extra checks
|
|
30
|
+
(DOMException && candidate instanceof DOMException)) &&
|
|
31
|
+
candidate.name === "AbortError")
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
/**
|
|
20
36
|
* Wraps a Promise and causes it to reject when the signal is aborted.
|
|
21
37
|
*
|
|
@@ -17,6 +17,15 @@ type StorageSubsystemEvents = {
|
|
|
17
17
|
numOps: number
|
|
18
18
|
numChanges: number
|
|
19
19
|
}) => void
|
|
20
|
+
"doc-compacted": (arg: {
|
|
21
|
+
documentId: DocumentId
|
|
22
|
+
durationMillis: number
|
|
23
|
+
}) => void
|
|
24
|
+
"doc-saved": (arg: {
|
|
25
|
+
documentId: DocumentId
|
|
26
|
+
durationMillis: number
|
|
27
|
+
sinceHeads: A.Heads
|
|
28
|
+
}) => void
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
/**
|
|
@@ -224,7 +233,17 @@ export class StorageSubsystem extends EventEmitter<StorageSubsystemEvents> {
|
|
|
224
233
|
documentId: DocumentId,
|
|
225
234
|
doc: A.Doc<unknown>
|
|
226
235
|
): Promise<void> {
|
|
227
|
-
const
|
|
236
|
+
const sinceHeads = this.#storedHeads.get(documentId) ?? []
|
|
237
|
+
const start = performance.now()
|
|
238
|
+
const binary = A.saveSince(doc, sinceHeads)
|
|
239
|
+
const end = performance.now()
|
|
240
|
+
console.log("emitting saved")
|
|
241
|
+
this.emit("doc-saved", {
|
|
242
|
+
documentId,
|
|
243
|
+
durationMillis: end - start,
|
|
244
|
+
sinceHeads,
|
|
245
|
+
})
|
|
246
|
+
|
|
228
247
|
if (binary && binary.length > 0) {
|
|
229
248
|
const key = [documentId, "incremental", keyHash(binary)]
|
|
230
249
|
this.#log(`Saving incremental ${key} for document ${documentId}`)
|
|
@@ -253,7 +272,11 @@ export class StorageSubsystem extends EventEmitter<StorageSubsystemEvents> {
|
|
|
253
272
|
): Promise<void> {
|
|
254
273
|
this.#compacting = true
|
|
255
274
|
|
|
275
|
+
const start = performance.now()
|
|
256
276
|
const binary = A.save(doc)
|
|
277
|
+
const end = performance.now()
|
|
278
|
+
this.emit("doc-compacted", { documentId, durationMillis: end - start })
|
|
279
|
+
|
|
257
280
|
const snapshotHash = headsHash(A.getHeads(doc))
|
|
258
281
|
const key = [documentId, "snapshot", snapshotHash]
|
|
259
282
|
const oldKeys = new Set(
|
|
@@ -191,7 +191,15 @@ export class DocSynchronizer extends Synchronizer {
|
|
|
191
191
|
this.#log(`sendSyncMessage ->${peerId}`)
|
|
192
192
|
|
|
193
193
|
this.#withSyncState(peerId, syncState => {
|
|
194
|
+
const start = performance.now()
|
|
194
195
|
const [newSyncState, message] = A.generateSyncMessage(doc, syncState)
|
|
196
|
+
const end = performance.now()
|
|
197
|
+
this.emit("metrics", {
|
|
198
|
+
type: "generate-sync-message",
|
|
199
|
+
documentId: this.#handle.documentId,
|
|
200
|
+
durationMillis: end - start,
|
|
201
|
+
})
|
|
202
|
+
|
|
195
203
|
if (message) {
|
|
196
204
|
this.#setSyncState(peerId, newSyncState)
|
|
197
205
|
const isNew = A.getHeads(doc).length === 0
|
package/test/Repo.test.ts
CHANGED
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
generateAutomergeUrl,
|
|
12
12
|
stringifyAutomergeUrl,
|
|
13
13
|
} from "../src/AutomergeUrl.js"
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
DocMetrics,
|
|
16
|
+
FindProgressWithMethods,
|
|
17
|
+
Repo,
|
|
18
|
+
ShareConfig,
|
|
19
|
+
} from "../src/Repo.js"
|
|
15
20
|
import { eventPromise } from "../src/helpers/eventPromise.js"
|
|
16
21
|
import { pause } from "../src/helpers/pause.js"
|
|
17
22
|
import {
|
|
@@ -2039,7 +2044,7 @@ describe("Repo.find() abort behavior", () => {
|
|
|
2039
2044
|
it("creates a document with the custom ID", async () => {
|
|
2040
2045
|
const id = new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0)))
|
|
2041
2046
|
const repo = new Repo({
|
|
2042
|
-
idFactory: () => id,
|
|
2047
|
+
idFactory: async () => id,
|
|
2043
2048
|
})
|
|
2044
2049
|
const handle = await repo.create2()
|
|
2045
2050
|
expect(handle.documentId).toBe("9HUp4wuzRMx9MRvN4x")
|
|
@@ -2049,7 +2054,7 @@ describe("Repo.find() abort behavior", () => {
|
|
|
2049
2054
|
const id = new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0)))
|
|
2050
2055
|
let calledHeads: Heads | null = null
|
|
2051
2056
|
const repo = new Repo({
|
|
2052
|
-
idFactory: (heads: Heads) => {
|
|
2057
|
+
idFactory: async (heads: Heads) => {
|
|
2053
2058
|
calledHeads = heads
|
|
2054
2059
|
return id
|
|
2055
2060
|
},
|
|
@@ -2063,7 +2068,7 @@ describe("Repo.find() abort behavior", () => {
|
|
|
2063
2068
|
const [aliceToBob, bobToAlice] = DummyNetworkAdapter.createConnectedPair()
|
|
2064
2069
|
const alice = new Repo({
|
|
2065
2070
|
peerId: "alice" as PeerId,
|
|
2066
|
-
idFactory: () =>
|
|
2071
|
+
idFactory: async () =>
|
|
2067
2072
|
new Uint8Array("custom-id".split("").map(c => c.charCodeAt(0))),
|
|
2068
2073
|
network: [aliceToBob],
|
|
2069
2074
|
})
|
|
@@ -2078,6 +2083,166 @@ describe("Repo.find() abort behavior", () => {
|
|
|
2078
2083
|
assert.deepStrictEqual(bobHandle.doc(), { foo: "bar" })
|
|
2079
2084
|
})
|
|
2080
2085
|
})
|
|
2086
|
+
|
|
2087
|
+
describe("emitted metrics", () => {
|
|
2088
|
+
async function setup(): Promise<{ alice: Repo; bob: Repo }> {
|
|
2089
|
+
const [aliceToBob, bobToAlice] = DummyNetworkAdapter.createConnectedPair()
|
|
2090
|
+
const alice = new Repo({
|
|
2091
|
+
peerId: "alice" as PeerId,
|
|
2092
|
+
network: [aliceToBob],
|
|
2093
|
+
})
|
|
2094
|
+
const bob = new Repo({ peerId: "bob" as PeerId, network: [bobToAlice] })
|
|
2095
|
+
aliceToBob.peerCandidate("bob" as PeerId)
|
|
2096
|
+
bobToAlice.peerCandidate("alice" as PeerId)
|
|
2097
|
+
|
|
2098
|
+
await pause(50)
|
|
2099
|
+
|
|
2100
|
+
return { alice, bob }
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
it("should emit events for receive sync message", async () => {
|
|
2104
|
+
const { alice, bob } = await setup()
|
|
2105
|
+
|
|
2106
|
+
const bobEvents: DocMetrics[] = []
|
|
2107
|
+
bob.on("doc-metrics", e => {
|
|
2108
|
+
if (e.type === "receive-sync-message") {
|
|
2109
|
+
bobEvents.push(e)
|
|
2110
|
+
}
|
|
2111
|
+
})
|
|
2112
|
+
|
|
2113
|
+
const handle = await alice.create2({ foo: "bar" })
|
|
2114
|
+
const bobHandle = await bob.find(handle.url)
|
|
2115
|
+
|
|
2116
|
+
assert.notEqual(bobEvents.length, 0)
|
|
2117
|
+
assert(
|
|
2118
|
+
bobEvents.every(
|
|
2119
|
+
e =>
|
|
2120
|
+
e.type === "receive-sync-message" &&
|
|
2121
|
+
e.documentId == handle.documentId &&
|
|
2122
|
+
e.durationMillis > 0
|
|
2123
|
+
)
|
|
2124
|
+
)
|
|
2125
|
+
|
|
2126
|
+
await Promise.all([bob.shutdown(), alice.shutdown()])
|
|
2127
|
+
})
|
|
2128
|
+
|
|
2129
|
+
it("should emit events for generate sync message", async () => {
|
|
2130
|
+
const { alice, bob } = await setup()
|
|
2131
|
+
|
|
2132
|
+
const bobEvents: DocMetrics[] = []
|
|
2133
|
+
bob.on("doc-metrics", e => {
|
|
2134
|
+
if (e.type === "generate-sync-message") {
|
|
2135
|
+
bobEvents.push(e)
|
|
2136
|
+
}
|
|
2137
|
+
})
|
|
2138
|
+
|
|
2139
|
+
const handle = await alice.create2({ foo: "bar" })
|
|
2140
|
+
const bobHandle = await bob.find(handle.url)
|
|
2141
|
+
|
|
2142
|
+
assert.notEqual(bobEvents.length, 0)
|
|
2143
|
+
assert(
|
|
2144
|
+
bobEvents.every(
|
|
2145
|
+
e =>
|
|
2146
|
+
e.type === "generate-sync-message" &&
|
|
2147
|
+
e.documentId == handle.documentId &&
|
|
2148
|
+
e.durationMillis > 0
|
|
2149
|
+
)
|
|
2150
|
+
)
|
|
2151
|
+
|
|
2152
|
+
await Promise.all([bob.shutdown(), alice.shutdown()])
|
|
2153
|
+
})
|
|
2154
|
+
|
|
2155
|
+
it("should emit events on compaction", async () => {
|
|
2156
|
+
const bob = new Repo({ storage: new DummyStorageAdapter() })
|
|
2157
|
+
// Create a doc and change it enough times to trigger compaction
|
|
2158
|
+
const doc = bob.create({ foo: "bar" })
|
|
2159
|
+
|
|
2160
|
+
const events: DocMetrics[] = []
|
|
2161
|
+
bob.on("doc-metrics", e => {
|
|
2162
|
+
if (e.type === "doc-compacted") {
|
|
2163
|
+
events.push(e)
|
|
2164
|
+
}
|
|
2165
|
+
})
|
|
2166
|
+
|
|
2167
|
+
for (let i = 0; i < 1000; i++) {
|
|
2168
|
+
doc.change(d => {
|
|
2169
|
+
A.splice(d, ["foo"], 0, 1, `${i}`)
|
|
2170
|
+
})
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
await pause(50)
|
|
2174
|
+
|
|
2175
|
+
assert.notEqual(events.length, 0)
|
|
2176
|
+
assert(
|
|
2177
|
+
events.every(
|
|
2178
|
+
e =>
|
|
2179
|
+
e.type === "doc-compacted" &&
|
|
2180
|
+
e.documentId == doc.documentId &&
|
|
2181
|
+
e.durationMillis > 0
|
|
2182
|
+
)
|
|
2183
|
+
)
|
|
2184
|
+
|
|
2185
|
+
await bob.shutdown()
|
|
2186
|
+
})
|
|
2187
|
+
|
|
2188
|
+
it("should emit events on save since", async () => {
|
|
2189
|
+
const bob = new Repo({
|
|
2190
|
+
storage: new DummyStorageAdapter(),
|
|
2191
|
+
saveDebounceRate: 10,
|
|
2192
|
+
})
|
|
2193
|
+
|
|
2194
|
+
const events: DocMetrics[] = []
|
|
2195
|
+
bob.on("doc-metrics", e => {
|
|
2196
|
+
console.log("event: ", e)
|
|
2197
|
+
if (e.type === "doc-saved") {
|
|
2198
|
+
events.push(e)
|
|
2199
|
+
}
|
|
2200
|
+
})
|
|
2201
|
+
|
|
2202
|
+
const doc = bob.create({ foo: "bar" })
|
|
2203
|
+
|
|
2204
|
+
// We have to save, then pause, then save again in order to trigger the
|
|
2205
|
+
// initial compaction and then get to the point where the save actually
|
|
2206
|
+
// triggers incremental saves rather than compactions. This is because the
|
|
2207
|
+
// logic in the storage adapter is designed to initially compact on every
|
|
2208
|
+
// change and only start incremental saves as the document gets a little
|
|
2209
|
+
// larger.
|
|
2210
|
+
|
|
2211
|
+
// First create enough changes to get past the "always compact" threshold
|
|
2212
|
+
for (let i = 0; i < 1000; i++) {
|
|
2213
|
+
doc.change(d => {
|
|
2214
|
+
A.splice(d, ["foo"], 0, 1, `${i}`)
|
|
2215
|
+
})
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
// Wait for the debounced save routine to finish
|
|
2219
|
+
await pause(20)
|
|
2220
|
+
|
|
2221
|
+
// Now trigger some changes which will cause incremental saves
|
|
2222
|
+
for (let i = 0; i < 10; i++) {
|
|
2223
|
+
doc.change(d => {
|
|
2224
|
+
A.splice(d, ["foo"], 0, 1, `${i}`)
|
|
2225
|
+
})
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
// Wait for the debounced save routine again
|
|
2229
|
+
await pause(20)
|
|
2230
|
+
|
|
2231
|
+
// Now actually test the events we got
|
|
2232
|
+
assert.notEqual(events.length, 0)
|
|
2233
|
+
assert(
|
|
2234
|
+
events.every(
|
|
2235
|
+
e =>
|
|
2236
|
+
e.type === "doc-saved" &&
|
|
2237
|
+
e.documentId == doc.documentId &&
|
|
2238
|
+
e.durationMillis > 0 &&
|
|
2239
|
+
A.hasHeads(doc.doc(), e.sinceHeads)
|
|
2240
|
+
)
|
|
2241
|
+
)
|
|
2242
|
+
|
|
2243
|
+
await bob.shutdown()
|
|
2244
|
+
})
|
|
2245
|
+
})
|
|
2081
2246
|
})
|
|
2082
2247
|
|
|
2083
2248
|
const warn = console.warn
|