@automerge/automerge-repo 1.1.0-alpha.1 → 1.1.0-alpha.2
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/Repo.d.ts +3 -8
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +14 -15
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.d.ts +14 -7
- package/dist/network/NetworkAdapter.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.js +1 -2
- package/dist/network/NetworkSubsystem.d.ts +4 -8
- package/dist/network/NetworkSubsystem.d.ts.map +1 -1
- package/dist/network/NetworkSubsystem.js +7 -10
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +6 -1
- package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.js +3 -3
- package/package.json +2 -2
- package/src/Repo.ts +21 -23
- package/src/index.ts +1 -0
- package/src/network/NetworkAdapter.ts +15 -8
- package/src/network/NetworkSubsystem.ts +18 -20
- package/src/storage/StorageSubsystem.ts +6 -1
- package/src/synchronizer/CollectionSynchronizer.ts +4 -3
package/dist/Repo.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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";
|
|
@@ -26,9 +26,9 @@ 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
|
-
|
|
31
|
+
peerMetadataByPeerId: Record<PeerId, PeerMetadata>;
|
|
32
32
|
constructor({ storage, network, peerId, sharePolicy, isEphemeral, }: RepoConfig);
|
|
33
33
|
/** Returns all the handles we have cached. */
|
|
34
34
|
get handles(): Record<DocumentId, DocHandle<any>>;
|
|
@@ -69,10 +69,6 @@ export declare class Repo extends EventEmitter<RepoEvents> {
|
|
|
69
69
|
subscribeToRemotes: (remotes: StorageId[]) => void;
|
|
70
70
|
storageId: () => Promise<StorageId | undefined>;
|
|
71
71
|
}
|
|
72
|
-
interface PersistanceInfo {
|
|
73
|
-
storageId: StorageId;
|
|
74
|
-
isEphemeral: boolean;
|
|
75
|
-
}
|
|
76
72
|
export interface RepoConfig {
|
|
77
73
|
/** Our unique identifier */
|
|
78
74
|
peerId?: PeerId;
|
|
@@ -113,5 +109,4 @@ export interface DocumentPayload {
|
|
|
113
109
|
export interface DeleteDocumentPayload {
|
|
114
110
|
documentId: DocumentId;
|
|
115
111
|
}
|
|
116
|
-
export {};
|
|
117
112
|
//# 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;AAEzE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;
|
|
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;AAEzE,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAI9C,8FAA8F;AAC9F;;;;;;GAMG;AACH,qBAAa,IAAK,SAAQ,YAAY,CAAC,UAAU,CAAC;;IAGhD,cAAc;IACd,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,cAAc;IACd,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IAEnC,mDAAmD;IACnD,cAAc;IACd,gBAAgB,SAAM;IAMtB,sDAAsD;IACtD,cAAc;IACd,WAAW,EAAE,WAAW,CAAmB;IAE3C,8GAA8G;IAC9G,cAAc;IACd,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAK;gBAI3C,EACV,OAAO,EACP,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAmC,GACpC,EAAE,UAAU;IAuQb,8CAA8C;IAC9C,IAAI,OAAO,uCAEV;IAED,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;IAED;;;;OAIG;IACH,MAAM,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;IA0BzB;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,CAAC,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAuBnC;;;OAGG;IACH,IAAI,CAAC,CAAC;IACJ,sDAAsD;IACtD,EAAE,EAAE,aAAa,GAChB,SAAS,CAAC,CAAC,CAAC;IAqBf,MAAM;IACJ,oDAAoD;IACpD,EAAE,EAAE,aAAa;IAWnB,kBAAkB,YAAa,SAAS,EAAE,UAGzC;IAED,SAAS,QAAa,QAAQ,SAAS,GAAG,SAAS,CAAC,CAMnD;CACF;AAED,MAAM,WAAW,UAAU;IACzB,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;8DAC0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB,gDAAgD;IAChD,OAAO,CAAC,EAAE,cAAc,CAAA;IAExB,oDAAoD;IACpD,OAAO,EAAE,cAAc,EAAE,CAAA;IAEzB;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED;;;;;;;KAOK;AACL,MAAM,MAAM,WAAW,GAAG,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,UAAU,KACpB,OAAO,CAAC,OAAO,CAAC,CAAA;AAGrB,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,CAAA;IACxC,6BAA6B;IAC7B,iBAAiB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;IACvD,4FAA4F;IAC5F,sBAAsB,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,IAAI,CAAA;CAC7D;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAA;CACvB"}
|
package/dist/Repo.js
CHANGED
|
@@ -31,9 +31,9 @@ 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
|
constructor({ storage, network, peerId, sharePolicy, isEphemeral = storage === undefined, }) {
|
|
39
39
|
super();
|
|
@@ -107,16 +107,17 @@ export class Repo extends EventEmitter {
|
|
|
107
107
|
this.storageSubsystem = storageSubsystem;
|
|
108
108
|
// NETWORK
|
|
109
109
|
// The network subsystem deals with sending and receiving messages to and from peers.
|
|
110
|
-
const
|
|
110
|
+
const myPeerMetadata = new Promise(async (resolve, reject) => resolve({
|
|
111
|
+
storageId: await storageSubsystem?.id(),
|
|
112
|
+
isEphemeral,
|
|
113
|
+
}));
|
|
114
|
+
const networkSubsystem = new NetworkSubsystem(network, peerId, myPeerMetadata);
|
|
111
115
|
this.networkSubsystem = networkSubsystem;
|
|
112
116
|
// When we get a new peer, register it with the synchronizer
|
|
113
|
-
networkSubsystem.on("peer", async ({ peerId,
|
|
117
|
+
networkSubsystem.on("peer", async ({ peerId, peerMetadata }) => {
|
|
114
118
|
this.#log("peer connected", { peerId });
|
|
115
|
-
if (
|
|
116
|
-
this.
|
|
117
|
-
storageId,
|
|
118
|
-
isEphemeral,
|
|
119
|
-
};
|
|
119
|
+
if (peerMetadata) {
|
|
120
|
+
this.peerMetadataByPeerId[peerId] = { ...peerMetadata };
|
|
120
121
|
}
|
|
121
122
|
this.sharePolicy(peerId)
|
|
122
123
|
.then(shouldShare => {
|
|
@@ -141,11 +142,10 @@ export class Repo extends EventEmitter {
|
|
|
141
142
|
this.#synchronizer.on("sync-state", message => {
|
|
142
143
|
this.#saveSyncState(message);
|
|
143
144
|
const handle = this.#handleCache[message.documentId];
|
|
144
|
-
const
|
|
145
|
-
if (!
|
|
145
|
+
const { storageId } = this.peerMetadataByPeerId[message.peerId] || {};
|
|
146
|
+
if (!storageId) {
|
|
146
147
|
return;
|
|
147
148
|
}
|
|
148
|
-
const { storageId } = info;
|
|
149
149
|
const heads = handle.getRemoteHeads(storageId);
|
|
150
150
|
const haveHeadsChanged = message.syncState.theirHeads &&
|
|
151
151
|
(!heads || !headsAreSame(heads, message.syncState.theirHeads));
|
|
@@ -208,11 +208,10 @@ export class Repo extends EventEmitter {
|
|
|
208
208
|
if (!this.storageSubsystem) {
|
|
209
209
|
return;
|
|
210
210
|
}
|
|
211
|
-
const
|
|
212
|
-
if (!
|
|
211
|
+
const { storageId, isEphemeral } = this.peerMetadataByPeerId[message.peerId] || {};
|
|
212
|
+
if (!storageId || isEphemeral) {
|
|
213
213
|
return;
|
|
214
214
|
}
|
|
215
|
-
const { storageId } = persistanceInfo;
|
|
216
215
|
let handler = this.#throttledSaveSyncStateHandlers[storageId];
|
|
217
216
|
if (!handler) {
|
|
218
217
|
handler = this.#throttledSaveSyncStateHandlers[storageId] = throttle(({ documentId, syncState }) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export { StorageAdapter } from "./storage/StorageAdapter.js";
|
|
|
35
35
|
export * as cbor from "./helpers/cbor.js";
|
|
36
36
|
export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedChangePayload, DocHandleEphemeralMessagePayload, DocHandleRemoteHeadsPayload, DocHandleEvents, DocHandleOptions, DocHandleOutboundEphemeralMessagePayload, HandleState, } from "./DocHandle.js";
|
|
37
37
|
export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
|
|
38
|
-
export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, } from "./network/NetworkAdapter.js";
|
|
38
|
+
export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, PeerMetadata, } from "./network/NetworkAdapter.js";
|
|
39
39
|
export type { DocumentUnavailableMessage, EphemeralMessage, Message, RepoMessage, RequestMessage, SyncMessage, } from "./network/messages.js";
|
|
40
40
|
export type { Chunk, ChunkInfo, ChunkType, StorageKey, StorageId, } from "./storage/types.js";
|
|
41
41
|
export * from "./types.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,eAAe;AACf,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA;AAIzC,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,wCAAwC,EACxC,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAE5D,eAAe;AACf,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA;AAIzC,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,6BAA6B,EAC7B,gCAAgC,EAChC,2BAA2B,EAC3B,eAAe,EACf,gBAAgB,EAChB,wCAAwC,EACxC,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAA;AAElB,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,EACvB,YAAY,GACb,MAAM,6BAA6B,CAAA;AAEpC,YAAY,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,WAAW,GACZ,MAAM,uBAAuB,CAAA;AAE9B,YAAY,EACV,KAAK,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,GACV,MAAM,oBAAoB,CAAA;AAE3B,cAAc,YAAY,CAAA"}
|
|
@@ -2,6 +2,16 @@ import { EventEmitter } from "eventemitter3";
|
|
|
2
2
|
import { PeerId } from "../types.js";
|
|
3
3
|
import { Message } from "./messages.js";
|
|
4
4
|
import { StorageId } from "../storage/types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Describes a peer intent to the system
|
|
7
|
+
* storageId: the key for syncState to decide what the other peer already has
|
|
8
|
+
* isEphemeral: to decide if we bother recording this peer's sync state
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export interface PeerMetadata {
|
|
12
|
+
storageId?: StorageId;
|
|
13
|
+
isEphemeral?: boolean;
|
|
14
|
+
}
|
|
5
15
|
/** An interface representing some way to connect to other peers
|
|
6
16
|
*
|
|
7
17
|
* @remarks
|
|
@@ -11,15 +21,13 @@ import { StorageId } from "../storage/types.js";
|
|
|
11
21
|
*/
|
|
12
22
|
export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
|
|
13
23
|
peerId?: PeerId;
|
|
14
|
-
|
|
15
|
-
isEphemeral: boolean;
|
|
24
|
+
peerMetadata?: PeerMetadata;
|
|
16
25
|
/** Called by the {@link Repo} to start the connection process
|
|
17
26
|
*
|
|
18
27
|
* @argument peerId - the peerId of this repo
|
|
19
|
-
* @argument
|
|
20
|
-
* @argument isEphemeral - weather or not the other end should persist our sync state
|
|
28
|
+
* @argument peerMetadata - how this adapter should present itself to other peers
|
|
21
29
|
*/
|
|
22
|
-
abstract connect(peerId: PeerId,
|
|
30
|
+
abstract connect(peerId: PeerId, peerMetadata?: PeerMetadata): void;
|
|
23
31
|
/** Called by the {@link Repo} to send a message to a peer
|
|
24
32
|
*
|
|
25
33
|
* @argument message - the message to send
|
|
@@ -45,8 +53,7 @@ export interface OpenPayload {
|
|
|
45
53
|
}
|
|
46
54
|
export interface PeerCandidatePayload {
|
|
47
55
|
peerId: PeerId;
|
|
48
|
-
|
|
49
|
-
isEphemeral: boolean;
|
|
56
|
+
peerMetadata: PeerMetadata;
|
|
50
57
|
}
|
|
51
58
|
export interface PeerDisconnectedPayload {
|
|
52
59
|
peerId: PeerId;
|
|
@@ -1 +1 @@
|
|
|
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;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,
|
|
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;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;GAMG;AACH,8BAAsB,cAAe,SAAQ,YAAY,CAAC,oBAAoB,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,YAAY,CAAA;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,YAAY,GAC1B,IAAI;IAEP;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAErC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,IAAI,IAAI;CAC5B;AAID,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,KAAK,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IAErC,yCAAyC;IACzC,KAAK,EAAE,MAAM,IAAI,CAAA;IAEjB,+DAA+D;IAC/D,gBAAgB,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAEzD,2EAA2E;IAC3E,mBAAmB,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAE/D,sEAAsE;IACtE,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;IACd,YAAY,EAAE,YAAY,CAAA;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { EventEmitter } from "eventemitter3";
|
|
2
2
|
import { PeerId } from "../types.js";
|
|
3
|
-
import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js";
|
|
3
|
+
import type { NetworkAdapter, PeerDisconnectedPayload, PeerMetadata } from "./NetworkAdapter.js";
|
|
4
4
|
import { MessageContents, RepoMessage } from "./messages.js";
|
|
5
|
-
import { StorageId } from "../storage/types.js";
|
|
6
5
|
export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
|
|
7
6
|
#private;
|
|
8
7
|
peerId: PeerId;
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
constructor(adapters: NetworkAdapter[], peerId: PeerId, storageId: Promise<StorageId | undefined>, // todo: we shouldn't pass a promise here
|
|
12
|
-
isEphemeral: boolean);
|
|
8
|
+
private peerMetadata;
|
|
9
|
+
constructor(adapters: NetworkAdapter[], peerId: PeerId, peerMetadata: Promise<PeerMetadata>);
|
|
13
10
|
addNetworkAdapter(networkAdapter: NetworkAdapter): void;
|
|
14
11
|
send(message: MessageContents): void;
|
|
15
12
|
isReady: () => boolean;
|
|
@@ -23,7 +20,6 @@ export interface NetworkSubsystemEvents {
|
|
|
23
20
|
}
|
|
24
21
|
export interface PeerPayload {
|
|
25
22
|
peerId: PeerId;
|
|
26
|
-
|
|
27
|
-
isEphemeral: boolean;
|
|
23
|
+
peerMetadata: PeerMetadata;
|
|
28
24
|
}
|
|
29
25
|
//# sourceMappingURL=NetworkSubsystem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAa,MAAM,aAAa,CAAA;AAC/C,OAAO,
|
|
1
|
+
{"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAa,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EACV,cAAc,EACd,uBAAuB,EACvB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AAQtB,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;IACb,OAAO,CAAC,YAAY;gBAFpB,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,QAAiB,EACtB,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC;IAO7C,iBAAiB,CAAC,cAAc,EAAE,cAAc;IAuEhD,IAAI,CAAC,OAAO,EAAE,eAAe;IAsC7B,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,WAAW,KAAK,IAAI,CAAA;IACvC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,YAAY,CAAA;CAC3B"}
|
|
@@ -4,8 +4,7 @@ import { isEphemeralMessage, isValidRepoMessage, } from "./messages.js";
|
|
|
4
4
|
const getEphemeralMessageSource = (message) => `${message.senderId}:${message.sessionId}`;
|
|
5
5
|
export class NetworkSubsystem extends EventEmitter {
|
|
6
6
|
peerId;
|
|
7
|
-
|
|
8
|
-
isEphemeral;
|
|
7
|
+
peerMetadata;
|
|
9
8
|
#log;
|
|
10
9
|
#adaptersByPeer = {};
|
|
11
10
|
#count = 0;
|
|
@@ -13,12 +12,10 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
13
12
|
#ephemeralSessionCounts = {};
|
|
14
13
|
#readyAdapterCount = 0;
|
|
15
14
|
#adapters = [];
|
|
16
|
-
constructor(adapters, peerId = randomPeerId(),
|
|
17
|
-
isEphemeral) {
|
|
15
|
+
constructor(adapters, peerId = randomPeerId(), peerMetadata) {
|
|
18
16
|
super();
|
|
19
17
|
this.peerId = peerId;
|
|
20
|
-
this.
|
|
21
|
-
this.isEphemeral = isEphemeral;
|
|
18
|
+
this.peerMetadata = peerMetadata;
|
|
22
19
|
this.#log = debug(`automerge-repo:network:${this.peerId}`);
|
|
23
20
|
adapters.forEach(a => this.addNetworkAdapter(a));
|
|
24
21
|
}
|
|
@@ -31,14 +28,14 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
31
28
|
this.emit("ready");
|
|
32
29
|
}
|
|
33
30
|
});
|
|
34
|
-
networkAdapter.on("peer-candidate", ({ peerId,
|
|
31
|
+
networkAdapter.on("peer-candidate", ({ peerId, peerMetadata }) => {
|
|
35
32
|
this.#log(`peer candidate: ${peerId} `);
|
|
36
33
|
// TODO: This is where authentication would happen
|
|
37
34
|
if (!this.#adaptersByPeer[peerId]) {
|
|
38
35
|
// TODO: handle losing a server here
|
|
39
36
|
this.#adaptersByPeer[peerId] = networkAdapter;
|
|
40
37
|
}
|
|
41
|
-
this.emit("peer", { peerId,
|
|
38
|
+
this.emit("peer", { peerId, peerMetadata });
|
|
42
39
|
});
|
|
43
40
|
networkAdapter.on("peer-disconnected", ({ peerId }) => {
|
|
44
41
|
this.#log(`peer disconnected: ${peerId} `);
|
|
@@ -70,8 +67,8 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
70
67
|
}
|
|
71
68
|
});
|
|
72
69
|
});
|
|
73
|
-
this.
|
|
74
|
-
networkAdapter.connect(this.peerId,
|
|
70
|
+
this.peerMetadata.then(peerMetadata => {
|
|
71
|
+
networkAdapter.connect(this.peerId, peerMetadata);
|
|
75
72
|
});
|
|
76
73
|
}
|
|
77
74
|
send(message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAK7D;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,cAAc;IAIpC,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,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmClE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAkEhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAM7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"StorageSubsystem.d.ts","sourceRoot":"","sources":["../../src/storage/StorageSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAI9C,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAyB,SAAS,EAAE,MAAM,YAAY,CAAA;AAK7D;;;GAGG;AACH,qBAAa,gBAAgB;;gBAef,cAAc,EAAE,cAAc;IAIpC,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,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAmClE;;;;;;OAMG;IACG,OAAO,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,UAAU;IAkEhC,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC;IAM7B,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,CAAC,CAAC,SAAS,GACrB,OAAO,CAAC,IAAI,CAAC;CA8CjB"}
|
|
@@ -217,6 +217,11 @@ export class StorageSubsystem {
|
|
|
217
217
|
incrementalSize += chunk.size;
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
|
-
|
|
220
|
+
// if the file is currently small, don't worry, just compact
|
|
221
|
+
// this might seem a bit arbitrary (1k is arbitrary) but is designed to ensure compaction
|
|
222
|
+
// for documents with only a single large change on top of an empty (or nearly empty) document
|
|
223
|
+
// for example: imported NPM modules, images, etc.
|
|
224
|
+
// if we have even more incrementals (so far) than the snapshot, compact
|
|
225
|
+
return snapshotSize < 1024 || incrementalSize >= snapshotSize;
|
|
221
226
|
}
|
|
222
227
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,UAAU,EAAe,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;
|
|
1
|
+
{"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AACjC,OAAO,EAAE,UAAU,EAAe,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAoD9B;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,UAAU;IAyBxC;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,UAAU;IAYlC,cAAc,CAAC,UAAU,EAAE,UAAU;IAIrC,2DAA2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM;IAgBtB,uDAAuD;IACvD,UAAU,CAAC,MAAM,EAAE,MAAM;IASzB,+CAA+C;IAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAEpB;CACF"}
|
|
@@ -32,11 +32,11 @@ export class CollectionSynchronizer extends Synchronizer {
|
|
|
32
32
|
if (!this.repo.storageSubsystem) {
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
35
|
+
const { storageId, isEphemeral } = this.repo.peerMetadataByPeerId[peerId] || {};
|
|
36
|
+
if (!storageId || isEphemeral) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
return this.repo.storageSubsystem.loadSyncState(handle.documentId,
|
|
39
|
+
return this.repo.storageSubsystem.loadSyncState(handle.documentId, storageId);
|
|
40
40
|
},
|
|
41
41
|
});
|
|
42
42
|
docSynchronizer.on("message", event => this.emit("message", event));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo",
|
|
3
|
-
"version": "1.1.0-alpha.
|
|
3
|
+
"version": "1.1.0-alpha.2",
|
|
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>",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"publishConfig": {
|
|
56
56
|
"access": "public"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "d73e71588c3835a172fdf4d19e56a1f946c041ed"
|
|
59
59
|
}
|
package/src/Repo.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./AutomergeUrl.js"
|
|
9
9
|
import { DocHandle, DocHandleEncodedChangePayload } from "./DocHandle.js"
|
|
10
10
|
import { throttle } from "./helpers/throttle.js"
|
|
11
|
-
import { NetworkAdapter } from "./network/NetworkAdapter.js"
|
|
11
|
+
import { NetworkAdapter, type PeerMetadata } from "./network/NetworkAdapter.js"
|
|
12
12
|
import { NetworkSubsystem } from "./network/NetworkSubsystem.js"
|
|
13
13
|
import { StorageAdapter } from "./storage/StorageAdapter.js"
|
|
14
14
|
import { StorageSubsystem } from "./storage/StorageSubsystem.js"
|
|
@@ -47,9 +47,9 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
47
47
|
/** @hidden */
|
|
48
48
|
sharePolicy: SharePolicy = async () => true
|
|
49
49
|
|
|
50
|
-
/** maps peer id to to
|
|
50
|
+
/** maps peer id to to persistence information (storageId, isEphemeral), access by collection synchronizer */
|
|
51
51
|
/** @hidden */
|
|
52
|
-
|
|
52
|
+
peerMetadataByPeerId: Record<PeerId, PeerMetadata> = {}
|
|
53
53
|
|
|
54
54
|
#remoteHeadsSubscriptions = new RemoteHeadsSubscriptions()
|
|
55
55
|
|
|
@@ -147,23 +147,28 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
147
147
|
|
|
148
148
|
// NETWORK
|
|
149
149
|
// The network subsystem deals with sending and receiving messages to and from peers.
|
|
150
|
+
|
|
151
|
+
const myPeerMetadata: Promise<PeerMetadata> = new Promise(
|
|
152
|
+
async (resolve, reject) =>
|
|
153
|
+
resolve({
|
|
154
|
+
storageId: await storageSubsystem?.id(),
|
|
155
|
+
isEphemeral,
|
|
156
|
+
} as PeerMetadata)
|
|
157
|
+
)
|
|
158
|
+
|
|
150
159
|
const networkSubsystem = new NetworkSubsystem(
|
|
151
160
|
network,
|
|
152
161
|
peerId,
|
|
153
|
-
|
|
154
|
-
isEphemeral
|
|
162
|
+
myPeerMetadata
|
|
155
163
|
)
|
|
156
164
|
this.networkSubsystem = networkSubsystem
|
|
157
165
|
|
|
158
166
|
// When we get a new peer, register it with the synchronizer
|
|
159
|
-
networkSubsystem.on("peer", async ({ peerId,
|
|
167
|
+
networkSubsystem.on("peer", async ({ peerId, peerMetadata }) => {
|
|
160
168
|
this.#log("peer connected", { peerId })
|
|
161
169
|
|
|
162
|
-
if (
|
|
163
|
-
this.
|
|
164
|
-
storageId,
|
|
165
|
-
isEphemeral,
|
|
166
|
-
}
|
|
170
|
+
if (peerMetadata) {
|
|
171
|
+
this.peerMetadataByPeerId[peerId] = { ...peerMetadata }
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
this.sharePolicy(peerId)
|
|
@@ -195,12 +200,11 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
195
200
|
|
|
196
201
|
const handle = this.#handleCache[message.documentId]
|
|
197
202
|
|
|
198
|
-
const
|
|
199
|
-
if (!
|
|
203
|
+
const { storageId } = this.peerMetadataByPeerId[message.peerId] || {}
|
|
204
|
+
if (!storageId) {
|
|
200
205
|
return
|
|
201
206
|
}
|
|
202
207
|
|
|
203
|
-
const { storageId } = info
|
|
204
208
|
const heads = handle.getRemoteHeads(storageId)
|
|
205
209
|
const haveHeadsChanged =
|
|
206
210
|
message.syncState.theirHeads &&
|
|
@@ -280,14 +284,13 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
280
284
|
return
|
|
281
285
|
}
|
|
282
286
|
|
|
283
|
-
const
|
|
287
|
+
const { storageId, isEphemeral } =
|
|
288
|
+
this.peerMetadataByPeerId[message.peerId] || {}
|
|
284
289
|
|
|
285
|
-
if (!
|
|
290
|
+
if (!storageId || isEphemeral) {
|
|
286
291
|
return
|
|
287
292
|
}
|
|
288
293
|
|
|
289
|
-
const { storageId } = persistanceInfo
|
|
290
|
-
|
|
291
294
|
let handler = this.#throttledSaveSyncStateHandlers[storageId]
|
|
292
295
|
if (!handler) {
|
|
293
296
|
handler = this.#throttledSaveSyncStateHandlers[storageId] = throttle(
|
|
@@ -453,11 +456,6 @@ export class Repo extends EventEmitter<RepoEvents> {
|
|
|
453
456
|
}
|
|
454
457
|
}
|
|
455
458
|
|
|
456
|
-
interface PersistanceInfo {
|
|
457
|
-
storageId: StorageId
|
|
458
|
-
isEphemeral: boolean
|
|
459
|
-
}
|
|
460
|
-
|
|
461
459
|
export interface RepoConfig {
|
|
462
460
|
/** Our unique identifier */
|
|
463
461
|
peerId?: PeerId
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,17 @@ import { PeerId } from "../types.js"
|
|
|
3
3
|
import { Message } from "./messages.js"
|
|
4
4
|
import { StorageId } from "../storage/types.js"
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Describes a peer intent to the system
|
|
8
|
+
* storageId: the key for syncState to decide what the other peer already has
|
|
9
|
+
* isEphemeral: to decide if we bother recording this peer's sync state
|
|
10
|
+
*
|
|
11
|
+
*/
|
|
12
|
+
export interface PeerMetadata {
|
|
13
|
+
storageId?: StorageId
|
|
14
|
+
isEphemeral?: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
/** An interface representing some way to connect to other peers
|
|
7
18
|
*
|
|
8
19
|
* @remarks
|
|
@@ -12,19 +23,16 @@ import { StorageId } from "../storage/types.js"
|
|
|
12
23
|
*/
|
|
13
24
|
export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
|
|
14
25
|
peerId?: PeerId // hmmm, maybe not
|
|
15
|
-
|
|
16
|
-
isEphemeral = true
|
|
26
|
+
peerMetadata?: PeerMetadata
|
|
17
27
|
|
|
18
28
|
/** Called by the {@link Repo} to start the connection process
|
|
19
29
|
*
|
|
20
30
|
* @argument peerId - the peerId of this repo
|
|
21
|
-
* @argument
|
|
22
|
-
* @argument isEphemeral - weather or not the other end should persist our sync state
|
|
31
|
+
* @argument peerMetadata - how this adapter should present itself to other peers
|
|
23
32
|
*/
|
|
24
33
|
abstract connect(
|
|
25
34
|
peerId: PeerId,
|
|
26
|
-
|
|
27
|
-
isEphemeral: boolean
|
|
35
|
+
peerMetadata?: PeerMetadata
|
|
28
36
|
): void
|
|
29
37
|
|
|
30
38
|
/** Called by the {@link Repo} to send a message to a peer
|
|
@@ -62,8 +70,7 @@ export interface OpenPayload {
|
|
|
62
70
|
|
|
63
71
|
export interface PeerCandidatePayload {
|
|
64
72
|
peerId: PeerId
|
|
65
|
-
|
|
66
|
-
isEphemeral: boolean
|
|
73
|
+
peerMetadata: PeerMetadata
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
export interface PeerDisconnectedPayload {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import debug from "debug"
|
|
2
2
|
import { EventEmitter } from "eventemitter3"
|
|
3
3
|
import { PeerId, SessionId } from "../types.js"
|
|
4
|
-
import {
|
|
4
|
+
import type {
|
|
5
|
+
NetworkAdapter,
|
|
6
|
+
PeerDisconnectedPayload,
|
|
7
|
+
PeerMetadata,
|
|
8
|
+
} from "./NetworkAdapter.js"
|
|
5
9
|
import {
|
|
6
10
|
EphemeralMessage,
|
|
7
11
|
MessageContents,
|
|
@@ -29,8 +33,7 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
|
|
|
29
33
|
constructor(
|
|
30
34
|
adapters: NetworkAdapter[],
|
|
31
35
|
public peerId = randomPeerId(),
|
|
32
|
-
private
|
|
33
|
-
private isEphemeral: boolean
|
|
36
|
+
private peerMetadata: Promise<PeerMetadata>
|
|
34
37
|
) {
|
|
35
38
|
super()
|
|
36
39
|
this.#log = debug(`automerge-repo:network:${this.peerId}`)
|
|
@@ -52,21 +55,17 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
|
|
|
52
55
|
}
|
|
53
56
|
})
|
|
54
57
|
|
|
55
|
-
networkAdapter.on(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.#log(`peer candidate: ${peerId} `)
|
|
58
|
+
networkAdapter.on("peer-candidate", ({ peerId, peerMetadata }) => {
|
|
59
|
+
this.#log(`peer candidate: ${peerId} `)
|
|
60
|
+
// TODO: This is where authentication would happen
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// TODO: handle losing a server here
|
|
64
|
-
this.#adaptersByPeer[peerId] = networkAdapter
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.emit("peer", { peerId, storageId, isEphemeral })
|
|
62
|
+
if (!this.#adaptersByPeer[peerId]) {
|
|
63
|
+
// TODO: handle losing a server here
|
|
64
|
+
this.#adaptersByPeer[peerId] = networkAdapter
|
|
68
65
|
}
|
|
69
|
-
|
|
66
|
+
|
|
67
|
+
this.emit("peer", { peerId, peerMetadata })
|
|
68
|
+
})
|
|
70
69
|
|
|
71
70
|
networkAdapter.on("peer-disconnected", ({ peerId }) => {
|
|
72
71
|
this.#log(`peer disconnected: ${peerId} `)
|
|
@@ -107,8 +106,8 @@ export class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
|
|
|
107
106
|
})
|
|
108
107
|
})
|
|
109
108
|
|
|
110
|
-
this.
|
|
111
|
-
networkAdapter.connect(this.peerId,
|
|
109
|
+
this.peerMetadata.then(peerMetadata => {
|
|
110
|
+
networkAdapter.connect(this.peerId, peerMetadata)
|
|
112
111
|
})
|
|
113
112
|
}
|
|
114
113
|
|
|
@@ -182,6 +181,5 @@ export interface NetworkSubsystemEvents {
|
|
|
182
181
|
|
|
183
182
|
export interface PeerPayload {
|
|
184
183
|
peerId: PeerId
|
|
185
|
-
|
|
186
|
-
isEphemeral: boolean
|
|
184
|
+
peerMetadata: PeerMetadata
|
|
187
185
|
}
|
|
@@ -279,6 +279,11 @@ export class StorageSubsystem {
|
|
|
279
279
|
incrementalSize += chunk.size
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
|
-
|
|
282
|
+
// if the file is currently small, don't worry, just compact
|
|
283
|
+
// this might seem a bit arbitrary (1k is arbitrary) but is designed to ensure compaction
|
|
284
|
+
// for documents with only a single large change on top of an empty (or nearly empty) document
|
|
285
|
+
// for example: imported NPM modules, images, etc.
|
|
286
|
+
// if we have even more incrementals (so far) than the snapshot, compact
|
|
287
|
+
return snapshotSize < 1024 || incrementalSize >= snapshotSize
|
|
283
288
|
}
|
|
284
289
|
}
|
|
@@ -42,14 +42,15 @@ export class CollectionSynchronizer extends Synchronizer {
|
|
|
42
42
|
return
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const
|
|
46
|
-
|
|
45
|
+
const { storageId, isEphemeral } =
|
|
46
|
+
this.repo.peerMetadataByPeerId[peerId] || {}
|
|
47
|
+
if (!storageId || isEphemeral) {
|
|
47
48
|
return
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
return this.repo.storageSubsystem.loadSyncState(
|
|
51
52
|
handle.documentId,
|
|
52
|
-
|
|
53
|
+
storageId
|
|
53
54
|
)
|
|
54
55
|
},
|
|
55
56
|
})
|