@automerge/automerge-repo 1.1.0-alpha.1 → 1.1.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -7
- package/dist/AutomergeUrl.js +2 -2
- package/dist/RemoteHeadsSubscriptions.d.ts +1 -0
- package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -1
- package/dist/RemoteHeadsSubscriptions.js +76 -16
- package/dist/Repo.d.ts +23 -10
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +103 -54
- package/dist/helpers/debounce.js +1 -1
- package/dist/helpers/pause.d.ts.map +1 -1
- package/dist/helpers/pause.js +2 -0
- package/dist/helpers/throttle.js +1 -1
- package/dist/helpers/withTimeout.d.ts.map +1 -1
- package/dist/helpers/withTimeout.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/network/NetworkAdapter.d.ts +14 -7
- package/dist/network/NetworkAdapter.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.js +3 -3
- package/dist/network/NetworkSubsystem.d.ts +4 -8
- package/dist/network/NetworkSubsystem.d.ts.map +1 -1
- package/dist/network/NetworkSubsystem.js +12 -13
- package/dist/network/messages.d.ts +48 -38
- package/dist/network/messages.d.ts.map +1 -1
- package/dist/network/messages.js +7 -9
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +7 -2
- package/dist/storage/keyHash.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.js +5 -3
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +20 -8
- package/dist/synchronizer/Synchronizer.d.ts +12 -3
- package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/AutomergeUrl.ts +2 -2
- package/src/RemoteHeadsSubscriptions.ts +85 -16
- package/src/Repo.ts +131 -68
- package/src/helpers/debounce.ts +1 -1
- package/src/helpers/pause.ts +4 -0
- package/src/helpers/throttle.ts +1 -1
- package/src/helpers/withTimeout.ts +2 -0
- package/src/index.ts +2 -1
- package/src/network/NetworkAdapter.ts +18 -12
- package/src/network/NetworkSubsystem.ts +23 -24
- package/src/network/messages.ts +77 -68
- package/src/storage/StorageSubsystem.ts +7 -2
- package/src/storage/keyHash.ts +2 -0
- package/src/synchronizer/CollectionSynchronizer.ts +7 -4
- package/src/synchronizer/DocSynchronizer.ts +27 -15
- package/src/synchronizer/Synchronizer.ts +13 -3
- package/test/RemoteHeadsSubscriptions.test.ts +34 -24
- package/test/Repo.test.ts +57 -2
- package/test/StorageSubsystem.test.ts +1 -1
- package/test/helpers/waitForMessages.ts +22 -0
- package/test/remoteHeads.test.ts +197 -72
- package/.eslintrc +0 -28
package/README.md
CHANGED
|
@@ -45,6 +45,10 @@ A `Repo` exposes these methods:
|
|
|
45
45
|
networks.
|
|
46
46
|
- `delete(docId: DocumentId)`
|
|
47
47
|
Deletes the local copy of a document from the local cache and local storage. _This does not currently delete the document from any other peers_.
|
|
48
|
+
- `import(binary: Uint8Array)`
|
|
49
|
+
Imports a document binary (from `export()` or `Automerge.save(doc)`) into the repo, returning a new handle
|
|
50
|
+
- `export(docId: DocumentId)`
|
|
51
|
+
Exports the document. Returns a Promise containing either the Uint8Array of the document or undefined if the document is currently unavailable. See the [Automerge binary format spec](https://automerge.org/automerge-binary-format-spec/) for more details on the shape of the Uint8Array.
|
|
48
52
|
- `.on("document", ({handle: DocHandle}) => void)`
|
|
49
53
|
Registers a callback to be fired each time a new document is loaded or created.
|
|
50
54
|
- `.on("delete-document", ({handle: DocHandle}) => void)`
|
|
@@ -64,7 +68,7 @@ the document.
|
|
|
64
68
|
|
|
65
69
|
A `DocHandle` also emits these events:
|
|
66
70
|
|
|
67
|
-
- `change({handle: DocHandle, patches: Patch[], patchInfo: PatchInfo})`
|
|
71
|
+
- `change({handle: DocHandle, patches: Patch[], patchInfo: PatchInfo})`
|
|
68
72
|
Called whenever the document changes, the handle's .doc
|
|
69
73
|
- `delete`
|
|
70
74
|
Called when the document is deleted locally.
|
|
@@ -85,11 +89,12 @@ network adapter:
|
|
|
85
89
|
const repo = new Repo({
|
|
86
90
|
network: [new BroadcastChannelNetworkAdapter()],
|
|
87
91
|
storage: new IndexedDBStorageAdapter(),
|
|
88
|
-
sharePolicy: async (peerId: PeerId, documentId: DocumentId) => true // this is the default
|
|
92
|
+
sharePolicy: async (peerId: PeerId, documentId: DocumentId) => true, // this is the default
|
|
89
93
|
})
|
|
90
94
|
```
|
|
91
95
|
|
|
92
96
|
### Share Policy
|
|
97
|
+
|
|
93
98
|
The share policy is used to determine which document in your repo should be _automatically_ shared with other peers. **The default setting is to share all documents with all peers.**
|
|
94
99
|
|
|
95
100
|
> **Warning**
|
|
@@ -99,7 +104,6 @@ You can override this by providing a custom share policy. The function should re
|
|
|
99
104
|
|
|
100
105
|
The share policy will not stop a document being _requested_ by another peer by its `DocumentId`.
|
|
101
106
|
|
|
102
|
-
```ts
|
|
103
107
|
## Starting the demo app
|
|
104
108
|
|
|
105
109
|
```bash
|
|
@@ -272,7 +276,8 @@ you'll need to manually copy the `rootDocId` value between the browsers.)
|
|
|
272
276
|
Originally authored by Peter van Hardenberg.
|
|
273
277
|
|
|
274
278
|
With gratitude for contributions by:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
+
|
|
280
|
+
- Herb Caudill
|
|
281
|
+
- Jeremy Rose
|
|
282
|
+
- Alex Currie-Clark
|
|
283
|
+
- Dylan Mackenzie
|
package/dist/AutomergeUrl.js
CHANGED
|
@@ -4,7 +4,7 @@ export const urlPrefix = "automerge:";
|
|
|
4
4
|
/** Given an Automerge URL, returns the DocumentId in both base58check-encoded form and binary form */
|
|
5
5
|
export const parseAutomergeUrl = (url) => {
|
|
6
6
|
const regex = new RegExp(`^${urlPrefix}(\\w+)$`);
|
|
7
|
-
const [
|
|
7
|
+
const [, docMatch] = url.match(regex) || [];
|
|
8
8
|
const documentId = docMatch;
|
|
9
9
|
const binaryDocumentId = documentIdToBinary(documentId);
|
|
10
10
|
if (!binaryDocumentId)
|
|
@@ -21,7 +21,7 @@ export const parseAutomergeUrl = (url) => {
|
|
|
21
21
|
* Throws on invalid input.
|
|
22
22
|
*/
|
|
23
23
|
export const stringifyAutomergeUrl = (arg) => {
|
|
24
|
-
|
|
24
|
+
const documentId = arg instanceof Uint8Array || typeof arg === "string"
|
|
25
25
|
? arg
|
|
26
26
|
: "documentId" in arg
|
|
27
27
|
? arg.documentId
|
|
@@ -36,6 +36,7 @@ export declare class RemoteHeadsSubscriptions extends EventEmitter<RemoteHeadsSu
|
|
|
36
36
|
handleImmediateRemoteHeadsChanged(documentId: DocumentId, storageId: StorageId, heads: A.Heads): void;
|
|
37
37
|
addGenerousPeer(peerId: PeerId): void;
|
|
38
38
|
removePeer(peerId: PeerId): void;
|
|
39
|
+
subscribePeerToDoc(peerId: PeerId, documentId: DocumentId): void;
|
|
39
40
|
}
|
|
40
41
|
export {};
|
|
41
42
|
//# sourceMappingURL=RemoteHeadsSubscriptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RemoteHeadsSubscriptions.d.ts","sourceRoot":"","sources":["../src/RemoteHeadsSubscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,sBAAsB,CAAA;AAChD,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;;
|
|
1
|
+
{"version":3,"file":"RemoteHeadsSubscriptions.d.ts","sourceRoot":"","sources":["../src/RemoteHeadsSubscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,sBAAsB,CAAA;AAChD,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"}
|
|
@@ -9,6 +9,8 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
9
9
|
#theirSubscriptions = new Map();
|
|
10
10
|
// Peers we will always share remote heads with even if they are not subscribed
|
|
11
11
|
#generousPeers = new Set();
|
|
12
|
+
// Documents each peer has open, we need this information so we only send remote heads of documents that the peer knows
|
|
13
|
+
#subscribedDocsByPeer = new Map();
|
|
12
14
|
#log = debug("automerge-repo:remote-heads-subscriptions");
|
|
13
15
|
subscribeToRemotes(remotes) {
|
|
14
16
|
this.#log("subscribeToRemotes", remotes);
|
|
@@ -47,10 +49,14 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
47
49
|
handleControlMessage(control) {
|
|
48
50
|
const remotesToAdd = [];
|
|
49
51
|
const remotesToRemove = [];
|
|
52
|
+
const addedRemotesWeKnow = [];
|
|
50
53
|
this.#log("handleControlMessage", control);
|
|
51
54
|
if (control.add) {
|
|
52
55
|
for (const remote of control.add) {
|
|
53
56
|
let theirSubs = this.#theirSubscriptions.get(remote);
|
|
57
|
+
if (this.#ourSubscriptions.has(remote) || theirSubs) {
|
|
58
|
+
addedRemotesWeKnow.push(remote);
|
|
59
|
+
}
|
|
54
60
|
if (!theirSubs) {
|
|
55
61
|
theirSubs = new Set();
|
|
56
62
|
this.#theirSubscriptions.set(remote, theirSubs);
|
|
@@ -80,6 +86,28 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
80
86
|
remove: remotesToRemove,
|
|
81
87
|
});
|
|
82
88
|
}
|
|
89
|
+
// send all our stored heads of documents the peer knows for the remotes they've added
|
|
90
|
+
for (const remote of addedRemotesWeKnow) {
|
|
91
|
+
const subscribedDocs = this.#subscribedDocsByPeer.get(control.senderId);
|
|
92
|
+
if (subscribedDocs) {
|
|
93
|
+
for (const documentId of subscribedDocs) {
|
|
94
|
+
const knownHeads = this.#knownHeads.get(documentId);
|
|
95
|
+
if (!knownHeads) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const lastHeads = knownHeads.get(remote);
|
|
99
|
+
if (lastHeads) {
|
|
100
|
+
this.emit("notify-remote-heads", {
|
|
101
|
+
targetId: control.senderId,
|
|
102
|
+
documentId,
|
|
103
|
+
heads: lastHeads.heads,
|
|
104
|
+
timestamp: lastHeads.timestamp,
|
|
105
|
+
storageId: remote,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
83
111
|
}
|
|
84
112
|
/** A peer we are not directly connected to has changed their heads */
|
|
85
113
|
handleRemoteHeads(msg) {
|
|
@@ -112,13 +140,15 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
112
140
|
const theirSubs = this.#theirSubscriptions.get(event.storageId);
|
|
113
141
|
if (theirSubs) {
|
|
114
142
|
for (const peerId of theirSubs) {
|
|
115
|
-
this
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
143
|
+
if (this.#isPeerSubscribedToDoc(peerId, event.documentId)) {
|
|
144
|
+
this.emit("notify-remote-heads", {
|
|
145
|
+
targetId: peerId,
|
|
146
|
+
documentId: event.documentId,
|
|
147
|
+
heads: event.remoteHeads,
|
|
148
|
+
timestamp: event.timestamp,
|
|
149
|
+
storageId: event.storageId,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
122
152
|
}
|
|
123
153
|
}
|
|
124
154
|
}
|
|
@@ -140,13 +170,15 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
140
170
|
const theirSubs = this.#theirSubscriptions.get(storageId);
|
|
141
171
|
if (theirSubs) {
|
|
142
172
|
for (const peerId of theirSubs) {
|
|
143
|
-
this
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
173
|
+
if (this.#isPeerSubscribedToDoc(peerId, documentId)) {
|
|
174
|
+
this.emit("notify-remote-heads", {
|
|
175
|
+
targetId: peerId,
|
|
176
|
+
documentId: documentId,
|
|
177
|
+
heads: heads,
|
|
178
|
+
timestamp: timestamp,
|
|
179
|
+
storageId: storageId,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
150
182
|
}
|
|
151
183
|
}
|
|
152
184
|
}
|
|
@@ -175,6 +207,7 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
175
207
|
this.#log("removePeer", peerId);
|
|
176
208
|
const remotesToRemove = [];
|
|
177
209
|
this.#generousPeers.delete(peerId);
|
|
210
|
+
this.#subscribedDocsByPeer.delete(peerId);
|
|
178
211
|
for (const [storageId, peerIds] of this.#theirSubscriptions) {
|
|
179
212
|
if (peerIds.has(peerId)) {
|
|
180
213
|
peerIds.delete(peerId);
|
|
@@ -191,6 +224,33 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
191
224
|
});
|
|
192
225
|
}
|
|
193
226
|
}
|
|
227
|
+
subscribePeerToDoc(peerId, documentId) {
|
|
228
|
+
let subscribedDocs = this.#subscribedDocsByPeer.get(peerId);
|
|
229
|
+
if (!subscribedDocs) {
|
|
230
|
+
subscribedDocs = new Set();
|
|
231
|
+
this.#subscribedDocsByPeer.set(peerId, subscribedDocs);
|
|
232
|
+
}
|
|
233
|
+
subscribedDocs.add(documentId);
|
|
234
|
+
const remoteHeads = this.#knownHeads.get(documentId);
|
|
235
|
+
if (remoteHeads) {
|
|
236
|
+
for (const [storageId, lastHeads] of remoteHeads) {
|
|
237
|
+
const subscribedPeers = this.#theirSubscriptions.get(storageId);
|
|
238
|
+
if (subscribedPeers && subscribedPeers.has(peerId)) {
|
|
239
|
+
this.emit("notify-remote-heads", {
|
|
240
|
+
targetId: peerId,
|
|
241
|
+
documentId,
|
|
242
|
+
heads: lastHeads.heads,
|
|
243
|
+
timestamp: lastHeads.timestamp,
|
|
244
|
+
storageId,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
#isPeerSubscribedToDoc(peerId, documentId) {
|
|
251
|
+
const subscribedDocs = this.#subscribedDocsByPeer.get(peerId);
|
|
252
|
+
return subscribedDocs && subscribedDocs.has(documentId);
|
|
253
|
+
}
|
|
194
254
|
/** Returns the (document, storageId) pairs which have changed after processing msg */
|
|
195
255
|
#changedHeads(msg) {
|
|
196
256
|
const changedHeads = [];
|
|
@@ -202,11 +262,11 @@ export class RemoteHeadsSubscriptions extends EventEmitter {
|
|
|
202
262
|
}
|
|
203
263
|
let remote = this.#knownHeads.get(documentId);
|
|
204
264
|
if (!remote) {
|
|
205
|
-
remote = new Map(
|
|
265
|
+
remote = new Map();
|
|
206
266
|
this.#knownHeads.set(documentId, remote);
|
|
207
267
|
}
|
|
208
268
|
const docRemote = remote.get(storageId);
|
|
209
|
-
if (docRemote && docRemote.timestamp
|
|
269
|
+
if (docRemote && docRemote.timestamp >= timestamp) {
|
|
210
270
|
continue;
|
|
211
271
|
}
|
|
212
272
|
else {
|
package/dist/Repo.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { EventEmitter } from "eventemitter3";
|
|
2
2
|
import { DocHandle } from "./DocHandle.js";
|
|
3
|
-
import { NetworkAdapter } from "./network/NetworkAdapter.js";
|
|
3
|
+
import { NetworkAdapter, type PeerMetadata } from "./network/NetworkAdapter.js";
|
|
4
4
|
import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
|
|
5
5
|
import { StorageAdapter } from "./storage/StorageAdapter.js";
|
|
6
6
|
import { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
7
|
-
import type { AnyDocumentId, DocumentId, PeerId } from "./types.js";
|
|
8
7
|
import { StorageId } from "./storage/types.js";
|
|
8
|
+
import type { AnyDocumentId, DocumentId, PeerId } from "./types.js";
|
|
9
9
|
/** A Repo is a collection of documents with networking, syncing, and storage capabilities. */
|
|
10
10
|
/** The `Repo` is the main entry point of this library
|
|
11
11
|
*
|
|
@@ -26,14 +26,15 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
26
26
|
/** By default, we share generously with all peers. */
|
|
27
27
|
/** @hidden */
|
|
28
28
|
sharePolicy: SharePolicy;
|
|
29
|
-
/** maps peer id to to
|
|
29
|
+
/** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
|
|
30
30
|
/** @hidden */
|
|
31
|
-
|
|
32
|
-
constructor({ storage, network, peerId, sharePolicy, isEphemeral, }: RepoConfig);
|
|
31
|
+
peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
|
|
32
|
+
constructor({ storage, network, peerId, sharePolicy, isEphemeral, enableRemoteHeadsGossiping, }: RepoConfig);
|
|
33
33
|
/** Returns all the handles we have cached. */
|
|
34
34
|
get handles(): Record<DocumentId, DocHandle<any>>;
|
|
35
35
|
/** Returns a list of all connected peer ids */
|
|
36
36
|
get peers(): PeerId[];
|
|
37
|
+
getStorageIdOfPeer(peerId: PeerId): StorageId | undefined;
|
|
37
38
|
/**
|
|
38
39
|
* Creates a new document and returns a handle to it. The initial value of the document is
|
|
39
40
|
* an empty object `{}`. Its documentId is generated by the system. we emit a `document` event
|
|
@@ -66,13 +67,22 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
66
67
|
delete(
|
|
67
68
|
/** The url or documentId of the handle to delete */
|
|
68
69
|
id: AnyDocumentId): void;
|
|
70
|
+
/**
|
|
71
|
+
* Exports a document to a binary format.
|
|
72
|
+
* @param id - The url or documentId of the handle to export
|
|
73
|
+
*
|
|
74
|
+
* @returns Promise<Uint8Array | undefined> - A Promise containing the binary document,
|
|
75
|
+
* or undefined if the document is unavailable.
|
|
76
|
+
*/
|
|
77
|
+
export(id: AnyDocumentId): Promise<Uint8Array | undefined>;
|
|
78
|
+
/**
|
|
79
|
+
* Imports document binary into the repo.
|
|
80
|
+
* @param binary - The binary to import
|
|
81
|
+
*/
|
|
82
|
+
import<T>(binary: Uint8Array): DocHandle<T>;
|
|
69
83
|
subscribeToRemotes: (remotes: StorageId[]) => void;
|
|
70
84
|
storageId: () => Promise<StorageId | undefined>;
|
|
71
85
|
}
|
|
72
|
-
interface PersistanceInfo {
|
|
73
|
-
storageId: StorageId;
|
|
74
|
-
isEphemeral: boolean;
|
|
75
|
-
}
|
|
76
86
|
export interface RepoConfig {
|
|
77
87
|
/** Our unique identifier */
|
|
78
88
|
peerId?: PeerId;
|
|
@@ -88,6 +98,10 @@ export interface RepoConfig {
|
|
|
88
98
|
* all peers). A server only syncs documents that a peer explicitly requests by ID.
|
|
89
99
|
*/
|
|
90
100
|
sharePolicy?: SharePolicy;
|
|
101
|
+
/**
|
|
102
|
+
* Whether to enable the experimental remote heads gossiping feature
|
|
103
|
+
*/
|
|
104
|
+
enableRemoteHeadsGossiping?: boolean;
|
|
91
105
|
}
|
|
92
106
|
/** A function that determines whether we should share a document with a peer
|
|
93
107
|
*
|
|
@@ -113,5 +127,4 @@ export interface DocumentPayload {
|
|
|
113
127
|
export interface DeleteDocumentPayload {
|
|
114
128
|
documentId: DocumentId;
|
|
115
129
|
}
|
|
116
|
-
export {};
|
|
117
130
|
//# sourceMappingURL=Repo.d.ts.map
|
package/dist/Repo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAM5C,OAAO,EAAE,SAAS,EAAiC,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"Repo.d.ts","sourceRoot":"","sources":["../src/Repo.ts"],"names":[],"mappings":"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"}
|
package/dist/Repo.js
CHANGED
|
@@ -3,12 +3,12 @@ import debug from "debug";
|
|
|
3
3
|
import { EventEmitter } from "eventemitter3";
|
|
4
4
|
import { generateAutomergeUrl, interpretAsDocumentId, parseAutomergeUrl, } from "./AutomergeUrl.js";
|
|
5
5
|
import { DocHandle } from "./DocHandle.js";
|
|
6
|
+
import { RemoteHeadsSubscriptions } from "./RemoteHeadsSubscriptions.js";
|
|
7
|
+
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
6
8
|
import { throttle } from "./helpers/throttle.js";
|
|
7
9
|
import { NetworkSubsystem } from "./network/NetworkSubsystem.js";
|
|
8
10
|
import { StorageSubsystem } from "./storage/StorageSubsystem.js";
|
|
9
11
|
import { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js";
|
|
10
|
-
import { RemoteHeadsSubscriptions } from "./RemoteHeadsSubscriptions.js";
|
|
11
|
-
import { headsAreSame } from "./helpers/headsAreSame.js";
|
|
12
12
|
/** A Repo is a collection of documents with networking, syncing, and storage capabilities. */
|
|
13
13
|
/** The `Repo` is the main entry point of this library
|
|
14
14
|
*
|
|
@@ -31,12 +31,14 @@ export class Repo extends EventEmitter {
|
|
|
31
31
|
/** By default, we share generously with all peers. */
|
|
32
32
|
/** @hidden */
|
|
33
33
|
sharePolicy = async () => true;
|
|
34
|
-
/** maps peer id to to
|
|
34
|
+
/** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
|
|
35
35
|
/** @hidden */
|
|
36
|
-
|
|
36
|
+
peerMetadataByPeerId = {};
|
|
37
37
|
#remoteHeadsSubscriptions = new RemoteHeadsSubscriptions();
|
|
38
|
-
|
|
38
|
+
#remoteHeadsGossipingEnabled = false;
|
|
39
|
+
constructor({ storage, network, peerId, sharePolicy, isEphemeral = storage === undefined, enableRemoteHeadsGossiping = false, }) {
|
|
39
40
|
super();
|
|
41
|
+
this.#remoteHeadsGossipingEnabled = enableRemoteHeadsGossiping;
|
|
40
42
|
this.#log = debug(`automerge-repo:repo`);
|
|
41
43
|
this.sharePolicy = sharePolicy ?? this.sharePolicy;
|
|
42
44
|
// DOC COLLECTION
|
|
@@ -48,7 +50,7 @@ export class Repo extends EventEmitter {
|
|
|
48
50
|
const saveFn = ({ handle, doc, }) => {
|
|
49
51
|
void storageSubsystem.saveDoc(handle.documentId, doc);
|
|
50
52
|
};
|
|
51
|
-
|
|
53
|
+
handle.on("heads-changed", throttle(saveFn, this.saveDebounceRate));
|
|
52
54
|
if (isNew) {
|
|
53
55
|
// this is a new document, immediately save it
|
|
54
56
|
await storageSubsystem.saveDoc(handle.documentId, handle.docSync());
|
|
@@ -101,26 +103,34 @@ export class Repo extends EventEmitter {
|
|
|
101
103
|
this.#log(`sending ${message.type} message to ${message.targetId}`);
|
|
102
104
|
networkSubsystem.send(message);
|
|
103
105
|
});
|
|
106
|
+
if (this.#remoteHeadsGossipingEnabled) {
|
|
107
|
+
this.#synchronizer.on("open-doc", ({ peerId, documentId }) => {
|
|
108
|
+
this.#remoteHeadsSubscriptions.subscribePeerToDoc(peerId, documentId);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
104
111
|
// STORAGE
|
|
105
112
|
// The storage subsystem has access to some form of persistence, and deals with save and loading documents.
|
|
106
113
|
const storageSubsystem = storage ? new StorageSubsystem(storage) : undefined;
|
|
107
114
|
this.storageSubsystem = storageSubsystem;
|
|
108
115
|
// NETWORK
|
|
109
116
|
// The network subsystem deals with sending and receiving messages to and from peers.
|
|
110
|
-
const
|
|
117
|
+
const myPeerMetadata = new Promise(
|
|
118
|
+
// eslint-disable-next-line no-async-promise-executor -- TODO: fix
|
|
119
|
+
async (resolve) => resolve({
|
|
120
|
+
storageId: await storageSubsystem?.id(),
|
|
121
|
+
isEphemeral,
|
|
122
|
+
}));
|
|
123
|
+
const networkSubsystem = new NetworkSubsystem(network, peerId, myPeerMetadata);
|
|
111
124
|
this.networkSubsystem = networkSubsystem;
|
|
112
125
|
// When we get a new peer, register it with the synchronizer
|
|
113
|
-
networkSubsystem.on("peer", async ({ peerId,
|
|
126
|
+
networkSubsystem.on("peer", async ({ peerId, peerMetadata }) => {
|
|
114
127
|
this.#log("peer connected", { peerId });
|
|
115
|
-
if (
|
|
116
|
-
this.
|
|
117
|
-
storageId,
|
|
118
|
-
isEphemeral,
|
|
119
|
-
};
|
|
128
|
+
if (peerMetadata) {
|
|
129
|
+
this.peerMetadataByPeerId[peerId] = { ...peerMetadata };
|
|
120
130
|
}
|
|
121
131
|
this.sharePolicy(peerId)
|
|
122
132
|
.then(shouldShare => {
|
|
123
|
-
if (shouldShare) {
|
|
133
|
+
if (shouldShare && this.#remoteHeadsGossipingEnabled) {
|
|
124
134
|
this.#remoteHeadsSubscriptions.addGenerousPeer(peerId);
|
|
125
135
|
}
|
|
126
136
|
})
|
|
@@ -141,57 +151,62 @@ export class Repo extends EventEmitter {
|
|
|
141
151
|
this.#synchronizer.on("sync-state", message => {
|
|
142
152
|
this.#saveSyncState(message);
|
|
143
153
|
const handle = this.#handleCache[message.documentId];
|
|
144
|
-
const
|
|
145
|
-
if (!
|
|
154
|
+
const { storageId } = this.peerMetadataByPeerId[message.peerId] || {};
|
|
155
|
+
if (!storageId) {
|
|
146
156
|
return;
|
|
147
157
|
}
|
|
148
|
-
const { storageId } = info;
|
|
149
158
|
const heads = handle.getRemoteHeads(storageId);
|
|
150
159
|
const haveHeadsChanged = message.syncState.theirHeads &&
|
|
151
160
|
(!heads || !headsAreSame(heads, message.syncState.theirHeads));
|
|
152
161
|
if (haveHeadsChanged) {
|
|
153
162
|
handle.setRemoteHeads(storageId, message.syncState.theirHeads);
|
|
154
|
-
if (storageId) {
|
|
163
|
+
if (storageId && this.#remoteHeadsGossipingEnabled) {
|
|
155
164
|
this.#remoteHeadsSubscriptions.handleImmediateRemoteHeadsChanged(message.documentId, storageId, message.syncState.theirHeads);
|
|
156
165
|
}
|
|
157
166
|
}
|
|
158
167
|
});
|
|
159
|
-
this.#
|
|
160
|
-
this.
|
|
161
|
-
type: "remote-heads-changed",
|
|
162
|
-
targetId: message.targetId,
|
|
163
|
-
documentId: message.documentId,
|
|
164
|
-
newHeads: {
|
|
165
|
-
[message.storageId]: {
|
|
166
|
-
heads: message.heads,
|
|
167
|
-
timestamp: message.timestamp,
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
this.#remoteHeadsSubscriptions.on("change-remote-subs", message => {
|
|
173
|
-
this.#log("change-remote-subs", message);
|
|
174
|
-
for (const peer of message.peers) {
|
|
168
|
+
if (this.#remoteHeadsGossipingEnabled) {
|
|
169
|
+
this.#remoteHeadsSubscriptions.on("notify-remote-heads", message => {
|
|
175
170
|
this.networkSubsystem.send({
|
|
176
|
-
type: "remote-
|
|
177
|
-
targetId:
|
|
178
|
-
|
|
179
|
-
|
|
171
|
+
type: "remote-heads-changed",
|
|
172
|
+
targetId: message.targetId,
|
|
173
|
+
documentId: message.documentId,
|
|
174
|
+
newHeads: {
|
|
175
|
+
[message.storageId]: {
|
|
176
|
+
heads: message.heads,
|
|
177
|
+
timestamp: message.timestamp,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
180
|
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
});
|
|
182
|
+
this.#remoteHeadsSubscriptions.on("change-remote-subs", message => {
|
|
183
|
+
this.#log("change-remote-subs", message);
|
|
184
|
+
for (const peer of message.peers) {
|
|
185
|
+
this.networkSubsystem.send({
|
|
186
|
+
type: "remote-subscription-change",
|
|
187
|
+
targetId: peer,
|
|
188
|
+
add: message.add,
|
|
189
|
+
remove: message.remove,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
this.#remoteHeadsSubscriptions.on("remote-heads-changed", message => {
|
|
194
|
+
const handle = this.#handleCache[message.documentId];
|
|
195
|
+
handle.setRemoteHeads(message.storageId, message.remoteHeads);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
187
198
|
}
|
|
188
199
|
#receiveMessage(message) {
|
|
189
200
|
switch (message.type) {
|
|
190
201
|
case "remote-subscription-change":
|
|
191
|
-
this.#
|
|
202
|
+
if (this.#remoteHeadsGossipingEnabled) {
|
|
203
|
+
this.#remoteHeadsSubscriptions.handleControlMessage(message);
|
|
204
|
+
}
|
|
192
205
|
break;
|
|
193
206
|
case "remote-heads-changed":
|
|
194
|
-
this.#
|
|
207
|
+
if (this.#remoteHeadsGossipingEnabled) {
|
|
208
|
+
this.#remoteHeadsSubscriptions.handleRemoteHeads(message);
|
|
209
|
+
}
|
|
195
210
|
break;
|
|
196
211
|
case "sync":
|
|
197
212
|
case "request":
|
|
@@ -204,22 +219,21 @@ export class Repo extends EventEmitter {
|
|
|
204
219
|
}
|
|
205
220
|
#throttledSaveSyncStateHandlers = {};
|
|
206
221
|
/** saves sync state throttled per storage id, if a peer doesn't have a storage id it's sync state is not persisted */
|
|
207
|
-
#saveSyncState(
|
|
222
|
+
#saveSyncState(payload) {
|
|
208
223
|
if (!this.storageSubsystem) {
|
|
209
224
|
return;
|
|
210
225
|
}
|
|
211
|
-
const
|
|
212
|
-
if (!
|
|
226
|
+
const { storageId, isEphemeral } = this.peerMetadataByPeerId[payload.peerId] || {};
|
|
227
|
+
if (!storageId || isEphemeral) {
|
|
213
228
|
return;
|
|
214
229
|
}
|
|
215
|
-
const { storageId } = persistanceInfo;
|
|
216
230
|
let handler = this.#throttledSaveSyncStateHandlers[storageId];
|
|
217
231
|
if (!handler) {
|
|
218
232
|
handler = this.#throttledSaveSyncStateHandlers[storageId] = throttle(({ documentId, syncState }) => {
|
|
219
|
-
this.storageSubsystem.saveSyncState(documentId, storageId, syncState);
|
|
233
|
+
void this.storageSubsystem.saveSyncState(documentId, storageId, syncState);
|
|
220
234
|
}, this.saveDebounceRate);
|
|
221
235
|
}
|
|
222
|
-
handler(
|
|
236
|
+
handler(payload);
|
|
223
237
|
}
|
|
224
238
|
/** Returns an existing handle if we have it; creates one otherwise. */
|
|
225
239
|
#getHandle(
|
|
@@ -245,6 +259,9 @@ export class Repo extends EventEmitter {
|
|
|
245
259
|
get peers() {
|
|
246
260
|
return this.#synchronizer.peers;
|
|
247
261
|
}
|
|
262
|
+
getStorageIdOfPeer(peerId) {
|
|
263
|
+
return this.peerMetadataByPeerId[peerId]?.storageId;
|
|
264
|
+
}
|
|
248
265
|
/**
|
|
249
266
|
* Creates a new document and returns a handle to it. The initial value of the document is
|
|
250
267
|
* an empty object `{}`. Its documentId is generated by the system. we emit a `document` event
|
|
@@ -335,9 +352,41 @@ export class Repo extends EventEmitter {
|
|
|
335
352
|
delete this.#handleCache[documentId];
|
|
336
353
|
this.emit("delete-document", { documentId });
|
|
337
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Exports a document to a binary format.
|
|
357
|
+
* @param id - The url or documentId of the handle to export
|
|
358
|
+
*
|
|
359
|
+
* @returns Promise<Uint8Array | undefined> - A Promise containing the binary document,
|
|
360
|
+
* or undefined if the document is unavailable.
|
|
361
|
+
*/
|
|
362
|
+
async export(id) {
|
|
363
|
+
const documentId = interpretAsDocumentId(id);
|
|
364
|
+
const handle = this.#getHandle(documentId, false);
|
|
365
|
+
const doc = await handle.doc();
|
|
366
|
+
if (!doc)
|
|
367
|
+
return undefined;
|
|
368
|
+
return Automerge.save(doc);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Imports document binary into the repo.
|
|
372
|
+
* @param binary - The binary to import
|
|
373
|
+
*/
|
|
374
|
+
import(binary) {
|
|
375
|
+
const doc = Automerge.load(binary);
|
|
376
|
+
const handle = this.create();
|
|
377
|
+
handle.update(() => {
|
|
378
|
+
return Automerge.clone(doc);
|
|
379
|
+
});
|
|
380
|
+
return handle;
|
|
381
|
+
}
|
|
338
382
|
subscribeToRemotes = (remotes) => {
|
|
339
|
-
this.#
|
|
340
|
-
|
|
383
|
+
if (this.#remoteHeadsGossipingEnabled) {
|
|
384
|
+
this.#log("subscribeToRemotes", { remotes });
|
|
385
|
+
this.#remoteHeadsSubscriptions.subscribeToRemotes(remotes);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
this.#log("WARN: subscribeToRemotes called but remote heads gossiping is not enabled");
|
|
389
|
+
}
|
|
341
390
|
};
|
|
342
391
|
storageId = async () => {
|
|
343
392
|
if (!this.storageSubsystem) {
|
package/dist/helpers/debounce.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pause.d.ts","sourceRoot":"","sources":["../../src/helpers/pause.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pause.d.ts","sourceRoot":"","sources":["../../src/helpers/pause.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,+BAC4C,CAAA;AAE9D,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|
package/dist/helpers/pause.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* c8 ignore start */
|
|
1
2
|
export const pause = (t = 0) => new Promise(resolve => setTimeout(() => resolve(), t));
|
|
2
3
|
export function rejectOnTimeout(promise, millis) {
|
|
3
4
|
return Promise.race([
|
|
@@ -7,3 +8,4 @@ export function rejectOnTimeout(promise, millis) {
|
|
|
7
8
|
}),
|
|
8
9
|
]);
|
|
9
10
|
}
|
|
11
|
+
/* c8 ignore end */
|
package/dist/helpers/throttle.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withTimeout.d.ts","sourceRoot":"","sources":["../../src/helpers/withTimeout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"withTimeout.d.ts","sourceRoot":"","sources":["../../src/helpers/withTimeout.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,eAAO,MAAM,WAAW,8BAEnB,MAAM,eAcV,CAAA;AAED,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* c8 ignore start */
|
|
1
2
|
/**
|
|
2
3
|
* If `promise` is resolved before `t` ms elapse, the timeout is cleared and the result of the
|
|
3
4
|
* promise is returned. If the timeout ends first, a `TimeoutError` is thrown.
|
|
@@ -20,3 +21,4 @@ export class TimeoutError extends Error {
|
|
|
20
21
|
this.name = "TimeoutError";
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
/* c8 ignore end */
|