@automerge/automerge-repo 1.0.0-alpha.2 → 1.0.0-alpha.4
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/DocCollection.d.ts +4 -2
- package/dist/DocCollection.d.ts.map +1 -1
- package/dist/DocCollection.js +20 -11
- package/dist/DocHandle.d.ts +34 -6
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +69 -9
- package/dist/DocUrl.d.ts +4 -4
- package/dist/DocUrl.d.ts.map +1 -1
- package/dist/DocUrl.js +9 -9
- package/dist/EphemeralData.d.ts +8 -16
- package/dist/EphemeralData.d.ts.map +1 -1
- package/dist/EphemeralData.js +1 -28
- package/dist/Repo.d.ts +0 -2
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +37 -39
- package/dist/helpers/cbor.d.ts +4 -0
- package/dist/helpers/cbor.d.ts.map +1 -0
- package/dist/helpers/cbor.js +8 -0
- package/dist/helpers/eventPromise.d.ts +1 -1
- package/dist/helpers/eventPromise.d.ts.map +1 -1
- package/dist/helpers/headsAreSame.d.ts +0 -1
- package/dist/helpers/headsAreSame.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 +15 -13
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/network/NetworkAdapter.d.ts +6 -15
- package/dist/network/NetworkAdapter.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.js +1 -1
- package/dist/network/NetworkSubsystem.d.ts +9 -6
- package/dist/network/NetworkSubsystem.d.ts.map +1 -1
- package/dist/network/NetworkSubsystem.js +69 -32
- package/dist/network/messages.d.ts +57 -0
- package/dist/network/messages.d.ts.map +1 -0
- package/dist/network/messages.js +21 -0
- package/dist/storage/StorageSubsystem.d.ts +1 -1
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +2 -2
- package/dist/synchronizer/CollectionSynchronizer.d.ts +3 -2
- package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.js +19 -13
- package/dist/synchronizer/DocSynchronizer.d.ts +9 -3
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +149 -34
- package/dist/synchronizer/Synchronizer.d.ts +4 -5
- package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
- package/dist/synchronizer/Synchronizer.js +1 -1
- package/dist/types.d.ts +1 -3
- package/dist/types.d.ts.map +1 -1
- package/fuzz/fuzz.ts +5 -5
- package/package.json +3 -3
- package/src/DocCollection.ts +23 -12
- package/src/DocHandle.ts +120 -13
- package/src/DocUrl.ts +10 -10
- package/src/EphemeralData.ts +6 -36
- package/src/Repo.ts +37 -55
- package/src/helpers/cbor.ts +10 -0
- package/src/helpers/eventPromise.ts +1 -1
- package/src/helpers/headsAreSame.ts +1 -1
- package/src/helpers/tests/network-adapter-tests.ts +18 -14
- package/src/index.ts +14 -2
- package/src/network/NetworkAdapter.ts +6 -22
- package/src/network/NetworkSubsystem.ts +94 -44
- package/src/network/messages.ts +123 -0
- package/src/storage/StorageSubsystem.ts +2 -2
- package/src/synchronizer/CollectionSynchronizer.ts +38 -19
- package/src/synchronizer/DocSynchronizer.ts +201 -43
- package/src/synchronizer/Synchronizer.ts +4 -9
- package/src/types.ts +4 -1
- package/test/CollectionSynchronizer.test.ts +6 -7
- package/test/DocCollection.test.ts +2 -2
- package/test/DocHandle.test.ts +32 -17
- package/test/DocSynchronizer.test.ts +85 -9
- package/test/Repo.test.ts +267 -63
- package/test/StorageSubsystem.test.ts +4 -5
- package/test/helpers/DummyNetworkAdapter.ts +12 -3
- package/test/helpers/DummyStorageAdapter.ts +1 -1
- package/tsconfig.json +4 -3
- package/test/EphemeralData.test.ts +0 -44
package/dist/Repo.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
+
import debug from "debug";
|
|
1
2
|
import { DocCollection } from "./DocCollection.js";
|
|
2
|
-
import { EphemeralData } from "./EphemeralData.js";
|
|
3
3
|
import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
|
|
4
4
|
import { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
5
5
|
import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
|
|
6
|
-
import debug from "debug";
|
|
7
6
|
/** A Repo is a DocCollection with networking, syncing, and storage capabilities. */
|
|
8
7
|
export class Repo extends DocCollection {
|
|
9
8
|
#log;
|
|
10
9
|
networkSubsystem;
|
|
11
10
|
storageSubsystem;
|
|
12
|
-
ephemeralData;
|
|
13
11
|
constructor({ storage, network, peerId, sharePolicy }) {
|
|
14
12
|
super();
|
|
15
13
|
this.#log = debug(`automerge-repo:repo`);
|
|
@@ -17,36 +15,60 @@ export class Repo extends DocCollection {
|
|
|
17
15
|
// DOC COLLECTION
|
|
18
16
|
// The `document` event is fired by the DocCollection any time we create a new document or look
|
|
19
17
|
// up a document by ID. We listen for it in order to wire up storage and network synchronization.
|
|
20
|
-
this.on("document", async ({ handle }) => {
|
|
18
|
+
this.on("document", async ({ handle, isNew }) => {
|
|
21
19
|
if (storageSubsystem) {
|
|
22
20
|
// Save when the document changes
|
|
23
21
|
handle.on("heads-changed", async ({ handle, doc }) => {
|
|
24
22
|
await storageSubsystem.saveDoc(handle.documentId, doc);
|
|
25
23
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
if (isNew) {
|
|
25
|
+
// this is a new document, immediately save it
|
|
26
|
+
await storageSubsystem.saveDoc(handle.documentId, handle.docSync());
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Try to load from disk
|
|
30
|
+
const loadedDoc = await storageSubsystem.loadDoc(handle.documentId);
|
|
31
|
+
if (loadedDoc) {
|
|
32
|
+
handle.update(() => loadedDoc);
|
|
33
|
+
}
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
|
-
handle.
|
|
36
|
+
handle.on("unavailable", () => {
|
|
37
|
+
this.#log("document unavailable", { documentId: handle.documentId });
|
|
38
|
+
this.emit("unavailable-document", {
|
|
39
|
+
documentId: handle.documentId,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
if (this.networkSubsystem.isReady()) {
|
|
43
|
+
handle.request();
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
handle.awaitNetwork();
|
|
47
|
+
this.networkSubsystem.whenReady().then(() => {
|
|
48
|
+
handle.networkReady();
|
|
49
|
+
}).catch(err => {
|
|
50
|
+
this.#log("error waiting for network", { err });
|
|
51
|
+
});
|
|
52
|
+
}
|
|
33
53
|
// Register the document with the synchronizer. This advertises our interest in the document.
|
|
34
54
|
synchronizer.addDocument(handle.documentId);
|
|
35
55
|
});
|
|
36
|
-
this.on("delete-document", ({
|
|
56
|
+
this.on("delete-document", ({ documentId }) => {
|
|
37
57
|
// TODO Pass the delete on to the network
|
|
38
58
|
// synchronizer.removeDocument(documentId)
|
|
39
59
|
if (storageSubsystem) {
|
|
40
|
-
storageSubsystem.remove(
|
|
60
|
+
storageSubsystem.remove(documentId).catch(err => {
|
|
61
|
+
this.#log("error deleting document", { documentId, err });
|
|
62
|
+
});
|
|
41
63
|
}
|
|
42
64
|
});
|
|
43
65
|
// SYNCHRONIZER
|
|
44
66
|
// The synchronizer uses the network subsystem to keep documents in sync with peers.
|
|
45
67
|
const synchronizer = new CollectionSynchronizer(this);
|
|
46
68
|
// When the synchronizer emits sync messages, send them to peers
|
|
47
|
-
synchronizer.on("message",
|
|
48
|
-
this.#log(`sending sync message to ${targetId}`);
|
|
49
|
-
networkSubsystem.
|
|
69
|
+
synchronizer.on("message", message => {
|
|
70
|
+
this.#log(`sending sync message to ${message.targetId}`);
|
|
71
|
+
networkSubsystem.send(message);
|
|
50
72
|
});
|
|
51
73
|
// STORAGE
|
|
52
74
|
// The storage subsystem has access to some form of persistence, and deals with save and loading documents.
|
|
@@ -67,31 +89,7 @@ export class Repo extends DocCollection {
|
|
|
67
89
|
});
|
|
68
90
|
// Handle incoming messages
|
|
69
91
|
networkSubsystem.on("message", async (msg) => {
|
|
70
|
-
|
|
71
|
-
// TODO: this demands a more principled way of associating channels with recipients
|
|
72
|
-
// Ephemeral channel ids start with "m/"
|
|
73
|
-
if (channelId.startsWith("m/")) {
|
|
74
|
-
// Ephemeral message
|
|
75
|
-
this.#log(`receiving ephemeral message from ${senderId}`);
|
|
76
|
-
ephemeralData.receive(senderId, channelId, message);
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
// Sync message
|
|
80
|
-
this.#log(`receiving sync message from ${senderId}`);
|
|
81
|
-
await synchronizer.receiveSyncMessage(senderId, channelId, message);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
// We establish a special channel for sync messages
|
|
85
|
-
networkSubsystem.join();
|
|
86
|
-
// EPHEMERAL DATA
|
|
87
|
-
// The ephemeral data subsystem uses the network to send and receive messages that are not
|
|
88
|
-
// persisted to storage, e.g. cursor position, presence, etc.
|
|
89
|
-
const ephemeralData = new EphemeralData();
|
|
90
|
-
this.ephemeralData = ephemeralData;
|
|
91
|
-
// Send ephemeral messages to peers
|
|
92
|
-
ephemeralData.on("message", ({ targetId, channelId, message, broadcast }) => {
|
|
93
|
-
this.#log(`sending ephemeral message to ${targetId}`);
|
|
94
|
-
networkSubsystem.sendMessage(targetId, channelId, message, broadcast);
|
|
92
|
+
await synchronizer.receiveMessage(msg);
|
|
95
93
|
});
|
|
96
94
|
}
|
|
97
95
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cbor.d.ts","sourceRoot":"","sources":["../../src/helpers/cbor.ts"],"names":[],"mappings":";AAEA,wBAAgB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAGvC;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,GAAG,CAEpD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import EventEmitter from "eventemitter3";
|
|
1
|
+
import { EventEmitter } from "eventemitter3";
|
|
2
2
|
/** Returns a promise that resolves when the given event is emitted on the given emitter. */
|
|
3
3
|
export declare const eventPromise: (emitter: EventEmitter, event: string) => Promise<any>;
|
|
4
4
|
export declare const eventPromises: (emitters: EventEmitter[], event: string) => Promise<any[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eventPromise.d.ts","sourceRoot":"","sources":["../../src/helpers/eventPromise.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"eventPromise.d.ts","sourceRoot":"","sources":["../../src/helpers/eventPromise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAE5C,4FAA4F;AAC5F,eAAO,MAAM,YAAY,YAAa,YAAY,SAAS,MAAM,iBACE,CAAA;AAEnE,eAAO,MAAM,aAAa,aAAc,YAAY,EAAE,SAAS,MAAM,mBAGpE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headsAreSame.d.ts","sourceRoot":"","sources":["../../src/helpers/headsAreSame.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"headsAreSame.d.ts","sourceRoot":"","sources":["../../src/helpers/headsAreSame.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,iCAExB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-adapter-tests.d.ts","sourceRoot":"","sources":["../../../src/helpers/tests/network-adapter-tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"network-adapter-tests.d.ts","sourceRoot":"","sources":["../../../src/helpers/tests/network-adapter-tests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAAc,MAAM,gBAAgB,CAAA;AAM9E;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CA8HrE;AAID,KAAK,OAAO,GAAG,cAAc,GAAG,cAAc,EAAE,CAAA;AAEhD,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC;IAClC,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;IACrC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,CAAC,CAAA"}
|
|
@@ -2,6 +2,7 @@ import { Repo } from "../../index.js";
|
|
|
2
2
|
import { eventPromise, eventPromises } from "../eventPromise.js";
|
|
3
3
|
import { assert } from "chai";
|
|
4
4
|
import { describe, it } from "mocha";
|
|
5
|
+
import { pause } from "../pause.js";
|
|
5
6
|
/**
|
|
6
7
|
* Runs a series of tests against a set of three peers, each represented by one or more instantiated
|
|
7
8
|
* network adapters.
|
|
@@ -38,14 +39,14 @@ export function runAdapterTests(_setup, title) {
|
|
|
38
39
|
});
|
|
39
40
|
// Bob receives the change
|
|
40
41
|
await eventPromise(bobHandle, "change");
|
|
41
|
-
assert.equal((await bobHandle.doc())
|
|
42
|
+
assert.equal((await bobHandle.doc())?.foo, "bar");
|
|
42
43
|
// Bob changes the document
|
|
43
44
|
bobHandle.change(d => {
|
|
44
45
|
d.foo = "baz";
|
|
45
46
|
});
|
|
46
47
|
// Alice receives the change
|
|
47
48
|
await eventPromise(aliceHandle, "change");
|
|
48
|
-
assert.equal((await aliceHandle.doc())
|
|
49
|
+
assert.equal((await aliceHandle.doc())?.foo, "baz");
|
|
49
50
|
};
|
|
50
51
|
// Run the test in both directions, in case they're different types of adapters
|
|
51
52
|
{
|
|
@@ -80,32 +81,33 @@ export function runAdapterTests(_setup, title) {
|
|
|
80
81
|
});
|
|
81
82
|
// Bob and Charlie receive the change
|
|
82
83
|
await eventPromises([bobHandle, charlieHandle], "change");
|
|
83
|
-
assert.equal((await bobHandle.doc())
|
|
84
|
-
assert.equal((await charlieHandle.doc())
|
|
84
|
+
assert.equal((await bobHandle.doc())?.foo, "bar");
|
|
85
|
+
assert.equal((await charlieHandle.doc())?.foo, "bar");
|
|
85
86
|
// Charlie changes the document
|
|
86
87
|
charlieHandle.change(d => {
|
|
87
88
|
d.foo = "baz";
|
|
88
89
|
});
|
|
89
90
|
// Alice and Bob receive the change
|
|
90
91
|
await eventPromises([aliceHandle, bobHandle], "change");
|
|
91
|
-
assert.equal((await bobHandle.doc())
|
|
92
|
-
assert.equal((await charlieHandle.doc())
|
|
92
|
+
assert.equal((await bobHandle.doc())?.foo, "baz");
|
|
93
|
+
assert.equal((await charlieHandle.doc())?.foo, "baz");
|
|
93
94
|
teardown();
|
|
94
95
|
});
|
|
95
|
-
|
|
96
|
-
// because the network has cycles (see #92)
|
|
97
|
-
it.skip("can broadcast a message", async () => {
|
|
96
|
+
it("can broadcast a message", async () => {
|
|
98
97
|
const { adapters, teardown } = await setup();
|
|
99
98
|
const [a, b, c] = adapters;
|
|
100
99
|
const aliceRepo = new Repo({ network: a, peerId: alice });
|
|
101
100
|
const bobRepo = new Repo({ network: b, peerId: bob });
|
|
102
101
|
const charlieRepo = new Repo({ network: c, peerId: charlie });
|
|
103
102
|
await eventPromises([aliceRepo, bobRepo, charlieRepo].map(r => r.networkSubsystem), "peer");
|
|
104
|
-
const
|
|
103
|
+
const aliceHandle = aliceRepo.create();
|
|
104
|
+
const charlieHandle = charlieRepo.find(aliceHandle.url);
|
|
105
|
+
// pause to give charlie a chance to let alice know it wants the doc
|
|
106
|
+
await pause(100);
|
|
105
107
|
const alicePresenceData = { presence: "alice" };
|
|
106
|
-
|
|
107
|
-
const {
|
|
108
|
-
assert.deepStrictEqual(
|
|
108
|
+
aliceHandle.broadcast(alicePresenceData);
|
|
109
|
+
const { message } = await eventPromise(charlieHandle, "ephemeral-message");
|
|
110
|
+
assert.deepStrictEqual(message, alicePresenceData);
|
|
109
111
|
teardown();
|
|
110
112
|
});
|
|
111
113
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ export { DocCollection } from "./DocCollection.js";
|
|
|
2
2
|
export { DocHandle, HandleState } from "./DocHandle.js";
|
|
3
3
|
export type { DocHandleChangePayload } from "./DocHandle.js";
|
|
4
4
|
export { NetworkAdapter } from "./network/NetworkAdapter.js";
|
|
5
|
-
export type {
|
|
5
|
+
export type { OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, } from "./network/NetworkAdapter.js";
|
|
6
|
+
export type { Message, NetworkAdapterMessage, EphemeralMessage, SyncMessage, } from "./network/messages.js";
|
|
6
7
|
export { NetworkSubsystem } from "./network/NetworkSubsystem.js";
|
|
7
8
|
export { Repo, type SharePolicy } from "./Repo.js";
|
|
8
9
|
export { StorageAdapter, type StorageKey } from "./storage/StorageAdapter.js";
|
|
@@ -10,4 +11,5 @@ export { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
|
10
11
|
export { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
|
|
11
12
|
export { parseAutomergeUrl, isValidAutomergeUrl, stringifyAutomergeUrl as generateAutomergeUrl, } from "./DocUrl.js";
|
|
12
13
|
export * from "./types.js";
|
|
14
|
+
export * as cbor from "./helpers/cbor.js";
|
|
13
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,YAAY,EACV,WAAW,EACX,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,6BAA6B,CAAA;AAMpC,YAAY,EACV,OAAO,EACP,qBAAqB,EACrB,gBAAgB,EAChB,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0CAA0C,CAAA;AACjF,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,IAAI,oBAAoB,GAC9C,MAAM,aAAa,CAAA;AACpB,cAAc,YAAY,CAAA;AAE1B,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -8,3 +8,4 @@ export { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
|
8
8
|
export { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
|
|
9
9
|
export { parseAutomergeUrl, isValidAutomergeUrl, stringifyAutomergeUrl as generateAutomergeUrl, } from "./DocUrl.js";
|
|
10
10
|
export * from "./types.js";
|
|
11
|
+
export * as cbor from "./helpers/cbor.js";
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import EventEmitter from "eventemitter3";
|
|
2
|
-
import { PeerId
|
|
1
|
+
import { EventEmitter } from "eventemitter3";
|
|
2
|
+
import { PeerId } from "../types.js";
|
|
3
|
+
import { Message } from "./messages.js";
|
|
3
4
|
export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
|
|
4
5
|
peerId?: PeerId;
|
|
5
6
|
abstract connect(url?: string): void;
|
|
6
|
-
abstract
|
|
7
|
+
abstract send(message: Message): void;
|
|
7
8
|
abstract join(): void;
|
|
8
9
|
abstract leave(): void;
|
|
9
10
|
}
|
|
10
11
|
export interface NetworkAdapterEvents {
|
|
11
|
-
|
|
12
|
+
ready: (payload: OpenPayload) => void;
|
|
12
13
|
close: () => void;
|
|
13
14
|
"peer-candidate": (payload: PeerCandidatePayload) => void;
|
|
14
15
|
"peer-disconnected": (payload: PeerDisconnectedPayload) => void;
|
|
15
|
-
message: (payload:
|
|
16
|
+
message: (payload: Message) => void;
|
|
16
17
|
}
|
|
17
18
|
export interface OpenPayload {
|
|
18
19
|
network: NetworkAdapter;
|
|
@@ -20,16 +21,6 @@ export interface OpenPayload {
|
|
|
20
21
|
export interface PeerCandidatePayload {
|
|
21
22
|
peerId: PeerId;
|
|
22
23
|
}
|
|
23
|
-
export interface MessagePayload {
|
|
24
|
-
targetId: PeerId;
|
|
25
|
-
channelId: ChannelId;
|
|
26
|
-
message: Uint8Array;
|
|
27
|
-
broadcast: boolean;
|
|
28
|
-
}
|
|
29
|
-
export interface InboundMessagePayload extends MessagePayload {
|
|
30
|
-
type?: string;
|
|
31
|
-
senderId: PeerId;
|
|
32
|
-
}
|
|
33
24
|
export interface PeerDisconnectedPayload {
|
|
34
25
|
peerId: PeerId;
|
|
35
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAEpC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAErC,QAAQ,CAAC,IAAI,IAAI,IAAI;IAErB,QAAQ,CAAC,KAAK,IAAI,IAAI;CACvB;AAID,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACrC,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IACzD,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import EventEmitter from "eventemitter3";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { EventEmitter } from "eventemitter3";
|
|
2
|
+
import { PeerId } from "../types.js";
|
|
3
|
+
import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js";
|
|
4
|
+
import { Message, MessageContents } from "./messages.js";
|
|
4
5
|
export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
|
|
5
6
|
#private;
|
|
6
|
-
private adapters;
|
|
7
7
|
peerId: PeerId;
|
|
8
8
|
constructor(adapters: NetworkAdapter[], peerId?: PeerId);
|
|
9
9
|
addNetworkAdapter(networkAdapter: NetworkAdapter): void;
|
|
10
|
-
|
|
10
|
+
send(message: MessageContents): void;
|
|
11
11
|
join(): void;
|
|
12
12
|
leave(): void;
|
|
13
|
+
isReady: () => boolean;
|
|
14
|
+
whenReady: () => Promise<void>;
|
|
13
15
|
}
|
|
14
16
|
export interface NetworkSubsystemEvents {
|
|
15
17
|
peer: (payload: PeerPayload) => void;
|
|
16
18
|
"peer-disconnected": (payload: PeerDisconnectedPayload) => void;
|
|
17
|
-
message: (payload:
|
|
19
|
+
message: (payload: Message) => void;
|
|
20
|
+
"ready": () => void;
|
|
18
21
|
}
|
|
19
22
|
export interface PeerPayload {
|
|
20
23
|
peerId: PeerId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAE7E,OAAO,EAIL,OAAO,EACP,eAAe,EAChB,MAAM,eAAe,CAAA;AAUtB,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;gBADb,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,SAAiB;IAOhC,iBAAiB,CAAC,cAAc,EAAE,cAAc;IAkEhD,IAAI,CAAC,OAAO,EAAE,eAAe;IA2B7B,IAAI;IAKJ,KAAK;IAKL,OAAO,gBAEN;IAED,SAAS,sBAUR;CACF;AAQD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC/D,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAA;IACnC,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
import EventEmitter from "eventemitter3";
|
|
1
|
+
import { EventEmitter } from "eventemitter3";
|
|
2
|
+
import { isEphemeralMessage, isValidMessage, } from "./messages.js";
|
|
2
3
|
import debug from "debug";
|
|
4
|
+
const getEphemeralMessageSource = (message) => `${message.senderId}:${message.sessionId}`;
|
|
3
5
|
export class NetworkSubsystem extends EventEmitter {
|
|
4
|
-
adapters;
|
|
5
6
|
peerId;
|
|
6
7
|
#log;
|
|
7
8
|
#adaptersByPeer = {};
|
|
9
|
+
#count = 0;
|
|
10
|
+
#sessionId = Math.random().toString(36).slice(2);
|
|
11
|
+
#ephemeralSessionCounts = {};
|
|
12
|
+
#readyAdapterCount = 0;
|
|
13
|
+
#adapters = [];
|
|
8
14
|
constructor(adapters, peerId = randomPeerId()) {
|
|
9
15
|
super();
|
|
10
|
-
this.adapters = adapters;
|
|
11
16
|
this.peerId = peerId;
|
|
12
17
|
this.#log = debug(`automerge-repo:network:${this.peerId}`);
|
|
13
|
-
|
|
18
|
+
adapters.forEach(a => this.addNetworkAdapter(a));
|
|
14
19
|
}
|
|
15
20
|
addNetworkAdapter(networkAdapter) {
|
|
16
|
-
|
|
21
|
+
this.#adapters.push(networkAdapter);
|
|
22
|
+
networkAdapter.once("ready", () => {
|
|
23
|
+
this.#readyAdapterCount++;
|
|
24
|
+
this.#log("Adapters ready: ", this.#readyAdapterCount, "/", this.#adapters.length);
|
|
25
|
+
if (this.#readyAdapterCount === this.#adapters.length) {
|
|
26
|
+
this.emit("ready");
|
|
27
|
+
}
|
|
28
|
+
});
|
|
17
29
|
networkAdapter.on("peer-candidate", ({ peerId }) => {
|
|
18
30
|
this.#log(`peer candidate: ${peerId} `);
|
|
19
31
|
// TODO: This is where authentication would happen
|
|
@@ -29,18 +41,19 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
29
41
|
this.emit("peer-disconnected", { peerId });
|
|
30
42
|
});
|
|
31
43
|
networkAdapter.on("message", msg => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
+
if (!isValidMessage(msg)) {
|
|
45
|
+
this.#log(`invalid message: ${JSON.stringify(msg)}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.#log(`message from ${msg.senderId}`);
|
|
49
|
+
if (isEphemeralMessage(msg)) {
|
|
50
|
+
const source = getEphemeralMessageSource(msg);
|
|
51
|
+
if (this.#ephemeralSessionCounts[source] === undefined ||
|
|
52
|
+
msg.count > this.#ephemeralSessionCounts[source]) {
|
|
53
|
+
this.#ephemeralSessionCounts[source] = msg.count;
|
|
54
|
+
this.emit("message", msg);
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
44
57
|
}
|
|
45
58
|
this.emit("message", msg);
|
|
46
59
|
});
|
|
@@ -52,33 +65,57 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
52
65
|
}
|
|
53
66
|
});
|
|
54
67
|
});
|
|
68
|
+
networkAdapter.connect(this.peerId);
|
|
55
69
|
networkAdapter.join();
|
|
56
70
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
send(message) {
|
|
72
|
+
const peer = this.#adaptersByPeer[message.targetId];
|
|
73
|
+
if (!peer) {
|
|
74
|
+
this.#log(`Tried to send message but peer not found: ${message.targetId}`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.#log(`Sending message to ${message.targetId}`);
|
|
78
|
+
if (isEphemeralMessage(message)) {
|
|
79
|
+
const outbound = "count" in message
|
|
80
|
+
? message
|
|
81
|
+
: {
|
|
82
|
+
...message,
|
|
83
|
+
count: ++this.#count,
|
|
84
|
+
sessionId: this.#sessionId,
|
|
85
|
+
senderId: this.peerId,
|
|
86
|
+
};
|
|
87
|
+
this.#log("Ephemeral message", outbound);
|
|
88
|
+
peer.send(outbound);
|
|
63
89
|
}
|
|
64
90
|
else {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
this.#log(`Sending message to ${peerId}`);
|
|
71
|
-
peer.sendMessage(peerId, channelId, message, false);
|
|
91
|
+
const outbound = { ...message, senderId: this.peerId };
|
|
92
|
+
this.#log("Sync message", outbound);
|
|
93
|
+
peer.send(outbound);
|
|
72
94
|
}
|
|
73
95
|
}
|
|
74
96
|
join() {
|
|
75
97
|
this.#log(`Joining network`);
|
|
76
|
-
this
|
|
98
|
+
this.#adapters.forEach(a => a.join());
|
|
77
99
|
}
|
|
78
100
|
leave() {
|
|
79
101
|
this.#log(`Leaving network`);
|
|
80
|
-
this
|
|
102
|
+
this.#adapters.forEach(a => a.leave());
|
|
81
103
|
}
|
|
104
|
+
isReady = () => {
|
|
105
|
+
return this.#readyAdapterCount === this.#adapters.length;
|
|
106
|
+
};
|
|
107
|
+
whenReady = async () => {
|
|
108
|
+
if (this.isReady()) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
return new Promise(resolve => {
|
|
113
|
+
this.once("ready", () => {
|
|
114
|
+
resolve();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
|
82
119
|
}
|
|
83
120
|
function randomPeerId() {
|
|
84
121
|
return `user-${Math.round(Math.random() * 100000)}`;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SessionId } from "../EphemeralData.js";
|
|
2
|
+
import { DocumentId, PeerId } from "../types.js";
|
|
3
|
+
export declare function isValidMessage(message: NetworkAdapterMessage): message is SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
|
|
4
|
+
export declare function isDocumentUnavailableMessage(message: NetworkAdapterMessage): message is DocumentUnavailableMessage;
|
|
5
|
+
export declare function isRequestMessage(message: NetworkAdapterMessage): message is RequestMessage;
|
|
6
|
+
export declare function isSyncMessage(message: NetworkAdapterMessage): message is SyncMessage;
|
|
7
|
+
export declare function isEphemeralMessage(message: NetworkAdapterMessage | MessageContents): message is EphemeralMessage | EphemeralMessageContents;
|
|
8
|
+
export interface SyncMessageEnvelope {
|
|
9
|
+
senderId: PeerId;
|
|
10
|
+
}
|
|
11
|
+
export interface SyncMessageContents {
|
|
12
|
+
type: "sync";
|
|
13
|
+
data: Uint8Array;
|
|
14
|
+
targetId: PeerId;
|
|
15
|
+
documentId: DocumentId;
|
|
16
|
+
}
|
|
17
|
+
export type SyncMessage = SyncMessageEnvelope & SyncMessageContents;
|
|
18
|
+
export interface EphemeralMessageEnvelope {
|
|
19
|
+
senderId: PeerId;
|
|
20
|
+
count: number;
|
|
21
|
+
sessionId: SessionId;
|
|
22
|
+
}
|
|
23
|
+
export interface EphemeralMessageContents {
|
|
24
|
+
type: "ephemeral";
|
|
25
|
+
targetId: PeerId;
|
|
26
|
+
documentId: DocumentId;
|
|
27
|
+
data: Uint8Array;
|
|
28
|
+
}
|
|
29
|
+
export type EphemeralMessage = EphemeralMessageEnvelope & EphemeralMessageContents;
|
|
30
|
+
export interface DocumentUnavailableMessageContents {
|
|
31
|
+
type: "doc-unavailable";
|
|
32
|
+
documentId: DocumentId;
|
|
33
|
+
targetId: PeerId;
|
|
34
|
+
}
|
|
35
|
+
export type DocumentUnavailableMessage = SyncMessageEnvelope & DocumentUnavailableMessageContents;
|
|
36
|
+
export interface RequestMessageContents {
|
|
37
|
+
type: "request";
|
|
38
|
+
data: Uint8Array;
|
|
39
|
+
targetId: PeerId;
|
|
40
|
+
documentId: DocumentId;
|
|
41
|
+
}
|
|
42
|
+
export type RequestMessage = SyncMessageEnvelope & RequestMessageContents;
|
|
43
|
+
export type MessageContents = SyncMessageContents | EphemeralMessageContents | RequestMessageContents | DocumentUnavailableMessageContents;
|
|
44
|
+
export type Message = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
|
|
45
|
+
export type SynchronizerMessage = SyncMessage | RequestMessage | DocumentUnavailableMessage | EphemeralMessage;
|
|
46
|
+
type ArriveMessage = {
|
|
47
|
+
senderId: PeerId;
|
|
48
|
+
type: "arrive";
|
|
49
|
+
};
|
|
50
|
+
type WelcomeMessage = {
|
|
51
|
+
senderId: PeerId;
|
|
52
|
+
targetId: PeerId;
|
|
53
|
+
type: "welcome";
|
|
54
|
+
};
|
|
55
|
+
export type NetworkAdapterMessage = ArriveMessage | WelcomeMessage | Message;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IACN,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,0BAA0B,CAU7B;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IAAI,0BAA0B,CAEvC;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IAAI,cAAc,CAE3B;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IAAI,WAAW,CAExB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,qBAAqB,GAAG,eAAe,GAC/C,OAAO,IAAI,gBAAgB,GAAG,wBAAwB,CAExD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,mBAAmB,CAAA;AAEnE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,wBAAwB,GACrD,wBAAwB,CAAA;AAE1B,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,iBAAiB,CAAA;IACvB,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,0BAA0B,GAAG,mBAAmB,GAC1D,kCAAkC,CAAA;AAEpC,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG,sBAAsB,CAAA;AAEzE,MAAM,MAAM,eAAe,GACvB,mBAAmB,GACnB,wBAAwB,GACxB,sBAAsB,GACtB,kCAAkC,CAAA;AAEtC,MAAM,MAAM,OAAO,GACf,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,0BAA0B,CAAA;AAE9B,MAAM,MAAM,mBAAmB,GAC3B,WAAW,GACX,cAAc,GACd,0BAA0B,GAC1B,gBAAgB,CAAA;AAEpB,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;CACf,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,SAAS,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function isValidMessage(message) {
|
|
2
|
+
return (typeof message === "object" &&
|
|
3
|
+
typeof message.type === "string" &&
|
|
4
|
+
typeof message.senderId === "string" &&
|
|
5
|
+
(isSyncMessage(message) ||
|
|
6
|
+
isEphemeralMessage(message) ||
|
|
7
|
+
isRequestMessage(message) ||
|
|
8
|
+
isDocumentUnavailableMessage(message)));
|
|
9
|
+
}
|
|
10
|
+
export function isDocumentUnavailableMessage(message) {
|
|
11
|
+
return message.type === "doc-unavailable";
|
|
12
|
+
}
|
|
13
|
+
export function isRequestMessage(message) {
|
|
14
|
+
return message.type === "request";
|
|
15
|
+
}
|
|
16
|
+
export function isSyncMessage(message) {
|
|
17
|
+
return message.type === "sync";
|
|
18
|
+
}
|
|
19
|
+
export function isEphemeralMessage(message) {
|
|
20
|
+
return message.type === "ephemeral";
|
|
21
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAc,MAAM,qBAAqB,CAAA;AAEhE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAa7C,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAelD,qBAAa,gBAAgB;;gBAMf,cAAc,EAAE,cAAc;IAqDpC,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IA0B/D,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAanE,MAAM,CAAC,UAAU,EAAE,UAAU;CAgCpC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as A from "@automerge/automerge";
|
|
1
|
+
import * as A from "@automerge/automerge/next";
|
|
2
2
|
import * as sha256 from "fast-sha256";
|
|
3
3
|
import { mergeArrays } from "../helpers/mergeArrays.js";
|
|
4
4
|
import debug from "debug";
|
|
@@ -11,7 +11,7 @@ function keyHash(binary) {
|
|
|
11
11
|
}
|
|
12
12
|
function headsHash(heads) {
|
|
13
13
|
let encoder = new TextEncoder();
|
|
14
|
-
let headsbinary = mergeArrays(heads.map(h => encoder.encode(h)));
|
|
14
|
+
let headsbinary = mergeArrays(heads.map((h) => encoder.encode(h)));
|
|
15
15
|
return keyHash(headsbinary);
|
|
16
16
|
}
|
|
17
17
|
export class StorageSubsystem {
|