@automerge/automerge-repo 1.0.0-alpha.2 → 1.0.0-alpha.3
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 +2 -1
- package/dist/DocCollection.d.ts.map +1 -1
- package/dist/DocCollection.js +17 -8
- package/dist/DocHandle.d.ts +27 -4
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +44 -6
- package/dist/DocUrl.d.ts +3 -3
- 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 +13 -33
- 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 +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.d.ts +4 -13
- package/dist/network/NetworkAdapter.d.ts.map +1 -1
- package/dist/network/NetworkSubsystem.d.ts +5 -4
- package/dist/network/NetworkSubsystem.d.ts.map +1 -1
- package/dist/network/NetworkSubsystem.js +39 -25
- 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/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 +145 -29
- package/dist/synchronizer/Synchronizer.d.ts +3 -4
- package/dist/synchronizer/Synchronizer.d.ts.map +1 -1
- package/dist/types.d.ts +1 -3
- package/dist/types.d.ts.map +1 -1
- package/fuzz/fuzz.ts +4 -4
- package/package.json +2 -2
- package/src/DocCollection.ts +19 -9
- package/src/DocHandle.ts +87 -10
- package/src/DocUrl.ts +9 -9
- package/src/EphemeralData.ts +6 -36
- package/src/Repo.ts +15 -49
- package/src/helpers/tests/network-adapter-tests.ts +18 -14
- package/src/index.ts +12 -2
- package/src/network/NetworkAdapter.ts +4 -20
- package/src/network/NetworkSubsystem.ts +61 -38
- package/src/network/messages.ts +123 -0
- package/src/synchronizer/CollectionSynchronizer.ts +38 -19
- package/src/synchronizer/DocSynchronizer.ts +196 -38
- package/src/synchronizer/Synchronizer.ts +3 -8
- package/src/types.ts +4 -1
- package/test/CollectionSynchronizer.test.ts +6 -7
- package/test/DocHandle.test.ts +28 -13
- package/test/DocSynchronizer.test.ts +85 -9
- package/test/Repo.test.ts +221 -59
- package/test/StorageSubsystem.test.ts +2 -2
- package/test/helpers/DummyNetworkAdapter.ts +1 -1
- package/tsconfig.json +2 -1
- package/test/EphemeralData.test.ts +0 -44
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";
|
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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import EventEmitter from "eventemitter3";
|
|
2
|
-
import { PeerId
|
|
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
|
}
|
|
@@ -12,7 +13,7 @@ export interface NetworkAdapterEvents {
|
|
|
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;AACxC,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"NetworkAdapter.d.ts","sourceRoot":"","sources":["../../src/network/NetworkAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AACxC,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,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,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,21 @@
|
|
|
1
1
|
import EventEmitter from "eventemitter3";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
7
|
private adapters;
|
|
7
8
|
peerId: PeerId;
|
|
8
9
|
constructor(adapters: NetworkAdapter[], peerId?: PeerId);
|
|
9
10
|
addNetworkAdapter(networkAdapter: NetworkAdapter): void;
|
|
10
|
-
|
|
11
|
+
send(message: MessageContents): void;
|
|
11
12
|
join(): void;
|
|
12
13
|
leave(): void;
|
|
13
14
|
}
|
|
14
15
|
export interface NetworkSubsystemEvents {
|
|
15
16
|
peer: (payload: PeerPayload) => void;
|
|
16
17
|
"peer-disconnected": (payload: PeerDisconnectedPayload) => void;
|
|
17
|
-
message: (payload:
|
|
18
|
+
message: (payload: Message) => void;
|
|
18
19
|
}
|
|
19
20
|
export interface PeerPayload {
|
|
20
21
|
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;AACxC,OAAO,
|
|
1
|
+
{"version":3,"file":"NetworkSubsystem.d.ts","sourceRoot":"","sources":["../../src/network/NetworkSubsystem.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAA;AACxC,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;;IAStE,OAAO,CAAC,QAAQ;IACT,MAAM;gBADL,QAAQ,EAAE,cAAc,EAAE,EAC3B,MAAM,SAAiB;IAOhC,iBAAiB,CAAC,cAAc,EAAE,cAAc;IA0DhD,IAAI,CAAC,OAAO,EAAE,eAAe;IA2B7B,IAAI;IAKJ,KAAK;CAIN;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;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
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
6
|
adapters;
|
|
5
7
|
peerId;
|
|
6
8
|
#log;
|
|
7
9
|
#adaptersByPeer = {};
|
|
10
|
+
#count = 0;
|
|
11
|
+
#sessionId = Math.random().toString(36).slice(2);
|
|
12
|
+
#ephemeralSessionCounts = {};
|
|
8
13
|
constructor(adapters, peerId = randomPeerId()) {
|
|
9
14
|
super();
|
|
10
15
|
this.adapters = adapters;
|
|
@@ -29,18 +34,19 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
29
34
|
this.emit("peer-disconnected", { peerId });
|
|
30
35
|
});
|
|
31
36
|
networkAdapter.on("message", msg => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
37
|
+
if (!isValidMessage(msg)) {
|
|
38
|
+
this.#log(`invalid message: ${JSON.stringify(msg)}`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.#log(`message from ${msg.senderId}`);
|
|
42
|
+
if (isEphemeralMessage(msg)) {
|
|
43
|
+
const source = getEphemeralMessageSource(msg);
|
|
44
|
+
if (this.#ephemeralSessionCounts[source] === undefined ||
|
|
45
|
+
msg.count > this.#ephemeralSessionCounts[source]) {
|
|
46
|
+
this.#ephemeralSessionCounts[source] = msg.count;
|
|
47
|
+
this.emit("message", msg);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
44
50
|
}
|
|
45
51
|
this.emit("message", msg);
|
|
46
52
|
});
|
|
@@ -54,21 +60,29 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
54
60
|
});
|
|
55
61
|
networkAdapter.join();
|
|
56
62
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
send(message) {
|
|
64
|
+
const peer = this.#adaptersByPeer[message.targetId];
|
|
65
|
+
if (!peer) {
|
|
66
|
+
this.#log(`Tried to send message but peer not found: ${message.targetId}`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
this.#log(`Sending message to ${message.targetId}`);
|
|
70
|
+
if (isEphemeralMessage(message)) {
|
|
71
|
+
const outbound = "count" in message
|
|
72
|
+
? message
|
|
73
|
+
: {
|
|
74
|
+
...message,
|
|
75
|
+
count: ++this.#count,
|
|
76
|
+
sessionId: this.#sessionId,
|
|
77
|
+
senderId: this.peerId,
|
|
78
|
+
};
|
|
79
|
+
this.#log("Ephemeral message", outbound);
|
|
80
|
+
peer.send(outbound);
|
|
63
81
|
}
|
|
64
82
|
else {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
this.#log(`Sending message to ${peerId}`);
|
|
71
|
-
peer.sendMessage(peerId, channelId, message, false);
|
|
83
|
+
const outbound = { ...message, senderId: this.peerId };
|
|
84
|
+
this.#log("Sync message", outbound);
|
|
85
|
+
peer.send(outbound);
|
|
72
86
|
}
|
|
73
87
|
}
|
|
74
88
|
join() {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SessionId } from "../EphemeralData";
|
|
2
|
+
import { DocumentId, PeerId } from "../types";
|
|
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,kBAAkB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAE7C,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,6 +1,7 @@
|
|
|
1
1
|
import { DocCollection } from "../DocCollection.js";
|
|
2
|
-
import {
|
|
2
|
+
import { PeerId, DocumentId } from "../types.js";
|
|
3
3
|
import { Synchronizer } from "./Synchronizer.js";
|
|
4
|
+
import { SynchronizerMessage } from "../network/messages.js";
|
|
4
5
|
/** A CollectionSynchronizer is responsible for synchronizing a DocCollection with peers. */
|
|
5
6
|
export declare class CollectionSynchronizer extends Synchronizer {
|
|
6
7
|
#private;
|
|
@@ -10,7 +11,7 @@ export declare class CollectionSynchronizer extends Synchronizer {
|
|
|
10
11
|
* When we receive a sync message for a document we haven't got in memory, we
|
|
11
12
|
* register it with the repo and start synchronizing
|
|
12
13
|
*/
|
|
13
|
-
|
|
14
|
+
receiveMessage(message: SynchronizerMessage): Promise<void>;
|
|
14
15
|
/**
|
|
15
16
|
* Starts synchronizing the given document with all peers that we share it generously with.
|
|
16
17
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAOnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"CollectionSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/CollectionSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAOnD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,OAAO,EAGL,mBAAmB,EAEpB,MAAM,wBAAwB,CAAA;AAG/B,4FAA4F;AAC5F,qBAAa,sBAAuB,SAAQ,YAAY;;IAU1C,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE,aAAa;IAiCvC;;;OAGG;IACG,cAAc,CAAC,OAAO,EAAE,mBAAmB;IAyBjD;;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;CAQ1B"}
|
|
@@ -10,6 +10,8 @@ export class CollectionSynchronizer extends Synchronizer {
|
|
|
10
10
|
#peers = new Set();
|
|
11
11
|
/** A map of documentIds to their synchronizers */
|
|
12
12
|
#docSynchronizers = {};
|
|
13
|
+
/** Used to determine if the document is know to the Collection and a synchronizer exists or is being set up */
|
|
14
|
+
#docSetUp = {};
|
|
13
15
|
constructor(repo) {
|
|
14
16
|
super();
|
|
15
17
|
this.repo = repo;
|
|
@@ -44,29 +46,30 @@ export class CollectionSynchronizer extends Synchronizer {
|
|
|
44
46
|
* When we receive a sync message for a document we haven't got in memory, we
|
|
45
47
|
* register it with the repo and start synchronizing
|
|
46
48
|
*/
|
|
47
|
-
async
|
|
48
|
-
log(`onSyncMessage: ${
|
|
49
|
-
const documentId =
|
|
49
|
+
async receiveMessage(message) {
|
|
50
|
+
log(`onSyncMessage: ${message.senderId}, ${message.documentId}, ${"data" in message ? message.data.byteLength + "bytes" : ""}`);
|
|
51
|
+
const documentId = message.documentId;
|
|
50
52
|
if (!documentId) {
|
|
51
53
|
throw new Error("received a message with an invalid documentId");
|
|
52
54
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
this.#docSetUp[documentId] = true;
|
|
56
|
+
const docSynchronizer = this.#fetchDocSynchronizer(documentId);
|
|
57
|
+
docSynchronizer.receiveMessage(message);
|
|
55
58
|
// Initiate sync with any new peers
|
|
56
59
|
const peers = await this.#documentGenerousPeers(documentId);
|
|
57
|
-
peers
|
|
58
|
-
.filter(peerId => !docSynchronizer.hasPeer(peerId))
|
|
59
|
-
.forEach(peerId => docSynchronizer.beginSync(peerId));
|
|
60
|
+
docSynchronizer.beginSync(peers.filter(peerId => !docSynchronizer.hasPeer(peerId)));
|
|
60
61
|
}
|
|
61
62
|
/**
|
|
62
63
|
* Starts synchronizing the given document with all peers that we share it generously with.
|
|
63
64
|
*/
|
|
64
65
|
addDocument(documentId) {
|
|
66
|
+
// HACK: this is a hack to prevent us from adding the same document twice
|
|
67
|
+
if (this.#docSetUp[documentId]) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
65
70
|
const docSynchronizer = this.#fetchDocSynchronizer(documentId);
|
|
66
71
|
void this.#documentGenerousPeers(documentId).then(peers => {
|
|
67
|
-
|
|
68
|
-
docSynchronizer.beginSync(peerId);
|
|
69
|
-
});
|
|
72
|
+
docSynchronizer.beginSync(peers);
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
75
|
// TODO: implement this
|
|
@@ -76,12 +79,15 @@ export class CollectionSynchronizer extends Synchronizer {
|
|
|
76
79
|
/** Adds a peer and maybe starts synchronizing with them */
|
|
77
80
|
addPeer(peerId) {
|
|
78
81
|
log(`adding ${peerId} & synchronizing with them`);
|
|
82
|
+
if (this.#peers.has(peerId)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
79
85
|
this.#peers.add(peerId);
|
|
80
86
|
for (const docSynchronizer of Object.values(this.#docSynchronizers)) {
|
|
81
87
|
const { documentId } = docSynchronizer;
|
|
82
|
-
|
|
88
|
+
this.repo.sharePolicy(peerId, documentId).then(okToShare => {
|
|
83
89
|
if (okToShare)
|
|
84
|
-
docSynchronizer.beginSync(peerId);
|
|
90
|
+
docSynchronizer.beginSync([peerId]);
|
|
85
91
|
});
|
|
86
92
|
}
|
|
87
93
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { DocHandle } from "../DocHandle.js";
|
|
2
|
-
import {
|
|
2
|
+
import { PeerId } from "../types.js";
|
|
3
3
|
import { Synchronizer } from "./Synchronizer.js";
|
|
4
|
+
import { EphemeralMessage, RequestMessage, SynchronizerMessage, SyncMessage } from "../network/messages.js";
|
|
5
|
+
type PeerDocumentStatus = "unknown" | "has" | "unavailable" | "wants";
|
|
4
6
|
/**
|
|
5
7
|
* DocSynchronizer takes a handle to an Automerge document, and receives & dispatches sync messages
|
|
6
8
|
* to bring it inline with all other peers' versions.
|
|
@@ -9,10 +11,14 @@ export declare class DocSynchronizer extends Synchronizer {
|
|
|
9
11
|
#private;
|
|
10
12
|
private handle;
|
|
11
13
|
constructor(handle: DocHandle<any>);
|
|
14
|
+
get peerStates(): Record<PeerId, PeerDocumentStatus>;
|
|
12
15
|
get documentId(): import("../types.js").DocumentId;
|
|
13
16
|
hasPeer(peerId: PeerId): boolean;
|
|
14
|
-
beginSync(
|
|
17
|
+
beginSync(peerIds: PeerId[]): void;
|
|
15
18
|
endSync(peerId: PeerId): void;
|
|
16
|
-
|
|
19
|
+
receiveMessage(message: SynchronizerMessage): void;
|
|
20
|
+
receiveEphemeralMessage(message: EphemeralMessage): void;
|
|
21
|
+
receiveSyncMessage(message: SyncMessage | RequestMessage): void;
|
|
17
22
|
}
|
|
23
|
+
export {};
|
|
18
24
|
//# sourceMappingURL=DocSynchronizer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGhD,OAAO,EACL,gBAAgB,EAIhB,cAAc,EACd,mBAAmB,EACnB,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAE/B,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAGrE;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAiBnC,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC;IAoB1C,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IAiHD,OAAO,CAAC,MAAM,EAAE,MAAM;IAItB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA8B3B,OAAO,CAAC,MAAM,EAAE,MAAM;IAKtB,cAAc,CAAC,OAAO,EAAE,mBAAmB;IAkB3C,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;IAuBjD,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;CA2EzD"}
|