@automerge/automerge-repo 1.0.18 → 1.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DocHandle.d.ts +7 -8
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +15 -20
- package/dist/RemoteHeadsSubscriptions.d.ts +41 -0
- package/dist/RemoteHeadsSubscriptions.d.ts.map +1 -0
- package/dist/RemoteHeadsSubscriptions.js +224 -0
- package/dist/Repo.d.ts +15 -1
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +118 -8
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.d.ts +8 -1
- package/dist/network/NetworkAdapter.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.js +2 -0
- package/dist/network/NetworkSubsystem.d.ts +7 -1
- package/dist/network/NetworkSubsystem.d.ts.map +1 -1
- package/dist/network/NetworkSubsystem.js +11 -4
- package/dist/network/messages.d.ts +24 -1
- package/dist/network/messages.d.ts.map +1 -1
- package/dist/network/messages.js +5 -1
- package/dist/storage/StorageSubsystem.d.ts +5 -3
- package/dist/storage/StorageSubsystem.d.ts.map +1 -1
- package/dist/storage/StorageSubsystem.js +17 -4
- package/dist/storage/types.d.ts +4 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.d.ts +2 -2
- package/dist/synchronizer/CollectionSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/CollectionSynchronizer.js +7 -3
- package/dist/synchronizer/DocSynchronizer.d.ts.map +1 -1
- package/dist/synchronizer/DocSynchronizer.js +0 -9
- package/package.json +3 -3
- package/src/DocHandle.ts +17 -22
- package/src/RemoteHeadsSubscriptions.ts +306 -0
- package/src/Repo.ts +173 -11
- package/src/index.ts +1 -0
- package/src/network/NetworkAdapter.ts +12 -1
- package/src/network/NetworkSubsystem.ts +24 -11
- package/src/network/messages.ts +30 -1
- package/src/storage/StorageSubsystem.ts +24 -6
- package/src/storage/types.ts +3 -0
- package/src/synchronizer/CollectionSynchronizer.ts +10 -5
- package/src/synchronizer/DocSynchronizer.ts +0 -12
- package/test/DocHandle.test.ts +1 -18
- package/test/RemoteHeadsSubscriptions.test.ts +343 -0
- package/test/Repo.test.ts +51 -15
- package/test/StorageSubsystem.test.ts +28 -6
- package/test/remoteHeads.test.ts +135 -0
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,6 @@ export type { DocHandleChangePayload, DocHandleDeletePayload, DocHandleEncodedCh
|
|
|
37
37
|
export type { DeleteDocumentPayload, DocumentPayload, RepoConfig, RepoEvents, SharePolicy, } from "./Repo.js";
|
|
38
38
|
export type { NetworkAdapterEvents, OpenPayload, PeerCandidatePayload, PeerDisconnectedPayload, } from "./network/NetworkAdapter.js";
|
|
39
39
|
export type { DocumentUnavailableMessage, EphemeralMessage, Message, RepoMessage, RequestMessage, SyncMessage, } from "./network/messages.js";
|
|
40
|
-
export type { Chunk, ChunkInfo, ChunkType, StorageKey, } from "./storage/types.js";
|
|
40
|
+
export type { Chunk, ChunkInfo, ChunkType, StorageKey, StorageId, } from "./storage/types.js";
|
|
41
41
|
export * from "./types.js";
|
|
42
42
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;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,GACxB,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,
|
|
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,GACxB,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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "eventemitter3";
|
|
2
2
|
import { PeerId } from "../types.js";
|
|
3
3
|
import { Message } from "./messages.js";
|
|
4
|
+
import { StorageId } from "../storage/types.js";
|
|
4
5
|
/** An interface representing some way to connect to other peers
|
|
5
6
|
*
|
|
6
7
|
* @remarks
|
|
@@ -10,11 +11,15 @@ import { Message } from "./messages.js";
|
|
|
10
11
|
*/
|
|
11
12
|
export declare abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
|
|
12
13
|
peerId?: PeerId;
|
|
14
|
+
storageId?: StorageId;
|
|
15
|
+
isEphemeral: boolean;
|
|
13
16
|
/** Called by the {@link Repo} to start the connection process
|
|
14
17
|
*
|
|
15
18
|
* @argument peerId - the peerId of this repo
|
|
19
|
+
* @argument storageId - the storage id of the peer
|
|
20
|
+
* @argument isEphemeral - weather or not the other end should persist our sync state
|
|
16
21
|
*/
|
|
17
|
-
abstract connect(peerId: PeerId): void;
|
|
22
|
+
abstract connect(peerId: PeerId, storageId: StorageId | undefined, isEphemeral: boolean): void;
|
|
18
23
|
/** Called by the {@link Repo} to send a message to a peer
|
|
19
24
|
*
|
|
20
25
|
* @argument message - the message to send
|
|
@@ -40,6 +45,8 @@ export interface OpenPayload {
|
|
|
40
45
|
}
|
|
41
46
|
export interface PeerCandidatePayload {
|
|
42
47
|
peerId: PeerId;
|
|
48
|
+
storageId?: StorageId;
|
|
49
|
+
isEphemeral: boolean;
|
|
43
50
|
}
|
|
44
51
|
export interface PeerDisconnectedPayload {
|
|
45
52
|
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;
|
|
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,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,UAAO;IAElB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,WAAW,EAAE,OAAO,GACnB,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,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;CACf"}
|
|
@@ -2,10 +2,14 @@ import { EventEmitter } from "eventemitter3";
|
|
|
2
2
|
import { PeerId } from "../types.js";
|
|
3
3
|
import { NetworkAdapter, PeerDisconnectedPayload } from "./NetworkAdapter.js";
|
|
4
4
|
import { MessageContents, RepoMessage } from "./messages.js";
|
|
5
|
+
import { StorageId } from "../storage/types.js";
|
|
5
6
|
export declare class NetworkSubsystem extends EventEmitter<NetworkSubsystemEvents> {
|
|
6
7
|
#private;
|
|
7
8
|
peerId: PeerId;
|
|
8
|
-
|
|
9
|
+
private storageId;
|
|
10
|
+
private isEphemeral;
|
|
11
|
+
constructor(adapters: NetworkAdapter[], peerId: PeerId, storageId: Promise<StorageId | undefined>, // todo: we shouldn't pass a promise here
|
|
12
|
+
isEphemeral: boolean);
|
|
9
13
|
addNetworkAdapter(networkAdapter: NetworkAdapter): void;
|
|
10
14
|
send(message: MessageContents): void;
|
|
11
15
|
isReady: () => boolean;
|
|
@@ -19,5 +23,7 @@ export interface NetworkSubsystemEvents {
|
|
|
19
23
|
}
|
|
20
24
|
export interface PeerPayload {
|
|
21
25
|
peerId: PeerId;
|
|
26
|
+
storageId?: StorageId;
|
|
27
|
+
isEphemeral: boolean;
|
|
22
28
|
}
|
|
23
29
|
//# 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,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;
|
|
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,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAEL,eAAe,EACf,WAAW,EAGZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAO/C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;;IAY/D,MAAM;IACb,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,WAAW;gBAHnB,QAAQ,EAAE,cAAc,EAAE,EACnB,MAAM,QAAiB,EACtB,SAAS,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,yCAAyC;IACpF,WAAW,EAAE,OAAO;IAO9B,iBAAiB,CAAC,cAAc,EAAE,cAAc;IA2EhD,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,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,WAAW,EAAE,OAAO,CAAA;CACrB"}
|
|
@@ -4,6 +4,8 @@ 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
|
+
storageId;
|
|
8
|
+
isEphemeral;
|
|
7
9
|
#log;
|
|
8
10
|
#adaptersByPeer = {};
|
|
9
11
|
#count = 0;
|
|
@@ -11,9 +13,12 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
11
13
|
#ephemeralSessionCounts = {};
|
|
12
14
|
#readyAdapterCount = 0;
|
|
13
15
|
#adapters = [];
|
|
14
|
-
constructor(adapters, peerId = randomPeerId()
|
|
16
|
+
constructor(adapters, peerId = randomPeerId(), storageId, // todo: we shouldn't pass a promise here
|
|
17
|
+
isEphemeral) {
|
|
15
18
|
super();
|
|
16
19
|
this.peerId = peerId;
|
|
20
|
+
this.storageId = storageId;
|
|
21
|
+
this.isEphemeral = isEphemeral;
|
|
17
22
|
this.#log = debug(`automerge-repo:network:${this.peerId}`);
|
|
18
23
|
adapters.forEach(a => this.addNetworkAdapter(a));
|
|
19
24
|
}
|
|
@@ -26,14 +31,14 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
26
31
|
this.emit("ready");
|
|
27
32
|
}
|
|
28
33
|
});
|
|
29
|
-
networkAdapter.on("peer-candidate", ({ peerId }) => {
|
|
34
|
+
networkAdapter.on("peer-candidate", ({ peerId, storageId, isEphemeral }) => {
|
|
30
35
|
this.#log(`peer candidate: ${peerId} `);
|
|
31
36
|
// TODO: This is where authentication would happen
|
|
32
37
|
if (!this.#adaptersByPeer[peerId]) {
|
|
33
38
|
// TODO: handle losing a server here
|
|
34
39
|
this.#adaptersByPeer[peerId] = networkAdapter;
|
|
35
40
|
}
|
|
36
|
-
this.emit("peer", { peerId });
|
|
41
|
+
this.emit("peer", { peerId, storageId, isEphemeral });
|
|
37
42
|
});
|
|
38
43
|
networkAdapter.on("peer-disconnected", ({ peerId }) => {
|
|
39
44
|
this.#log(`peer disconnected: ${peerId} `);
|
|
@@ -65,7 +70,9 @@ export class NetworkSubsystem extends EventEmitter {
|
|
|
65
70
|
}
|
|
66
71
|
});
|
|
67
72
|
});
|
|
68
|
-
|
|
73
|
+
this.storageId.then(storageId => {
|
|
74
|
+
networkAdapter.connect(this.peerId, storageId, this.isEphemeral);
|
|
75
|
+
});
|
|
69
76
|
}
|
|
70
77
|
send(message) {
|
|
71
78
|
const peer = this.#adaptersByPeer[message.targetId];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SyncState } from "@automerge/automerge";
|
|
2
2
|
import { DocumentId, PeerId, SessionId } from "../types.js";
|
|
3
|
+
import { StorageId } from "../storage/types.js";
|
|
3
4
|
/**
|
|
4
5
|
* A sync message for a particular document
|
|
5
6
|
*/
|
|
@@ -76,8 +77,28 @@ export type AuthMessage<TPayload = any> = {
|
|
|
76
77
|
/** The payload of the auth message (up to the specific auth provider) */
|
|
77
78
|
payload: TPayload;
|
|
78
79
|
};
|
|
80
|
+
export type RemoteSubscriptionControlMessage = {
|
|
81
|
+
type: "remote-subscription-change";
|
|
82
|
+
senderId: PeerId;
|
|
83
|
+
targetId: PeerId;
|
|
84
|
+
add?: StorageId[];
|
|
85
|
+
remove?: StorageId[];
|
|
86
|
+
};
|
|
87
|
+
export type RemoteHeadsChanged = {
|
|
88
|
+
type: "remote-heads-changed";
|
|
89
|
+
senderId: PeerId;
|
|
90
|
+
targetId: PeerId;
|
|
91
|
+
documentId: DocumentId;
|
|
92
|
+
newHeads: {
|
|
93
|
+
[key: StorageId]: {
|
|
94
|
+
heads: string[];
|
|
95
|
+
timestamp: number;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
};
|
|
79
99
|
/** These are message types that a {@link NetworkAdapter} surfaces to a {@link Repo}. */
|
|
80
|
-
export type RepoMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
|
|
100
|
+
export type RepoMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage | RemoteSubscriptionControlMessage | RemoteHeadsChanged;
|
|
101
|
+
export type DocMessage = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
|
|
81
102
|
/** These are all the message types that a {@link NetworkAdapter} might see. */
|
|
82
103
|
export type Message = RepoMessage | AuthMessage;
|
|
83
104
|
/**
|
|
@@ -95,4 +116,6 @@ export declare const isDocumentUnavailableMessage: (msg: Message) => msg is Docu
|
|
|
95
116
|
export declare const isRequestMessage: (msg: Message) => msg is RequestMessage;
|
|
96
117
|
export declare const isSyncMessage: (msg: Message) => msg is SyncMessage;
|
|
97
118
|
export declare const isEphemeralMessage: (msg: Message) => msg is EphemeralMessage;
|
|
119
|
+
export declare const isRemoteSubscriptionControlMessage: (msg: Message) => msg is RemoteSubscriptionControlMessage;
|
|
120
|
+
export declare const isRemoteHeadsChanged: (msg: Message) => msg is RemoteHeadsChanged;
|
|
98
121
|
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAA;IAEZ,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,iCAAiC;IACjC,IAAI,EAAE,UAAU,CAAA;IAEhB,0DAA0D;IAC1D,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;;;;;KASK;AACL,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,WAAW,CAAA;IAEjB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAA;IAEb,8GAA8G;IAC9G,SAAS,EAAE,SAAS,CAAA;IAEpB,+CAA+C;IAC/C,UAAU,EAAE,UAAU,CAAA;IAEtB,qCAAqC;IACrC,IAAI,EAAE,UAAU,CAAA;CACjB,CAAA;AAED,uHAAuH;AACvH,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,iBAAiB,CAAA;IAEvB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,yDAAyD;IACzD,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;KAKK;AACL,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAA;IAEf,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,yCAAyC;IACzC,IAAI,EAAE,UAAU,CAAA;IAEhB,4CAA4C;IAC5C,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,WAAW,CAAC,QAAQ,GAAG,GAAG,IAAI;IACxC,IAAI,EAAE,MAAM,CAAA;IAEZ,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAEhB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAEhB,yEAAyE;IACzE,OAAO,EAAE,QAAQ,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,4BAA4B,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;CACtB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,sBAAsB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE;QAAC,CAAC,GAAG,EAAE,SAAS,GAAG;YAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAC,CAAA;KAAC,CAAC;CACpE,CAAA;AAED,wFAAwF;AACxF,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,0BAA0B,GAC1B,gCAAgC,GAChC,kBAAkB,CAAA;AAEtB,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,gBAAgB,GAAG,cAAc,GAAG,0BAA0B,CAAA;AAErG,+EAA+E;AAC/E,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,WAAW,CAAA;AAE/C;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IACrD,CAAC,SAAS,gBAAgB,GACtB,IAAI,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,CAAC,GAC3C,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;AAEzB,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;CACrB;AAID,eAAO,MAAM,kBAAkB,YAAa,OAAO,2BASjB,CAAA;AAGlC,eAAO,MAAM,4BAA4B,QAAS,OAAO,sCACzB,CAAA;AAEhC,eAAO,MAAM,gBAAgB,QAAS,OAAO,0BACrB,CAAA;AAExB,eAAO,MAAM,aAAa,QAAS,OAAO,uBACrB,CAAA;AAErB,eAAO,MAAM,kBAAkB,QAAS,OAAO,4BACrB,CAAA;AAE1B,eAAO,MAAM,kCAAkC,QAAS,OAAO,4CACpB,CAAA;AAE3C,eAAO,MAAM,oBAAoB,QAAS,OAAO,8BACZ,CAAA"}
|
package/dist/network/messages.js
CHANGED
|
@@ -5,9 +5,13 @@ export const isValidRepoMessage = (message) => typeof message === "object" &&
|
|
|
5
5
|
(isSyncMessage(message) ||
|
|
6
6
|
isEphemeralMessage(message) ||
|
|
7
7
|
isRequestMessage(message) ||
|
|
8
|
-
isDocumentUnavailableMessage(message)
|
|
8
|
+
isDocumentUnavailableMessage(message) ||
|
|
9
|
+
isRemoteSubscriptionControlMessage(message) ||
|
|
10
|
+
isRemoteHeadsChanged(message));
|
|
9
11
|
// prettier-ignore
|
|
10
12
|
export const isDocumentUnavailableMessage = (msg) => msg.type === "doc-unavailable";
|
|
11
13
|
export const isRequestMessage = (msg) => msg.type === "request";
|
|
12
14
|
export const isSyncMessage = (msg) => msg.type === "sync";
|
|
13
15
|
export const isEphemeralMessage = (msg) => msg.type === "ephemeral";
|
|
16
|
+
export const isRemoteSubscriptionControlMessage = (msg) => msg.type === "remote-subscription-change";
|
|
17
|
+
export const isRemoteHeadsChanged = (msg) => msg.type === "remote-heads-changed";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as A from "@automerge/automerge/next";
|
|
2
|
-
import {
|
|
2
|
+
import { type DocumentId } from "../types.js";
|
|
3
3
|
import { StorageAdapter } from "./StorageAdapter.js";
|
|
4
|
+
import { StorageId } from "./types.js";
|
|
4
5
|
/**
|
|
5
6
|
* The storage subsystem is responsible for saving and loading Automerge documents to and from
|
|
6
7
|
* storage adapter. It also provides a generic key/value storage interface for other uses.
|
|
@@ -8,6 +9,7 @@ import { StorageAdapter } from "./StorageAdapter.js";
|
|
|
8
9
|
export declare class StorageSubsystem {
|
|
9
10
|
#private;
|
|
10
11
|
constructor(storageAdapter: StorageAdapter);
|
|
12
|
+
id(): Promise<StorageId>;
|
|
11
13
|
/** Loads a value from storage. */
|
|
12
14
|
load(
|
|
13
15
|
/** Namespace to prevent collisions with other users of the storage subsystem. */
|
|
@@ -44,7 +46,7 @@ export declare class StorageSubsystem {
|
|
|
44
46
|
* Removes the Automerge document with the given ID from storage
|
|
45
47
|
*/
|
|
46
48
|
removeDoc(documentId: DocumentId): Promise<void>;
|
|
47
|
-
loadSyncState(documentId: DocumentId,
|
|
48
|
-
saveSyncState(documentId: DocumentId,
|
|
49
|
+
loadSyncState(documentId: DocumentId, storageId: StorageId): Promise<A.SyncState | undefined>;
|
|
50
|
+
saveSyncState(documentId: DocumentId, storageId: StorageId, syncState: A.SyncState): Promise<void>;
|
|
49
51
|
}
|
|
50
52
|
//# sourceMappingURL=StorageSubsystem.d.ts.map
|
|
@@ -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,
|
|
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;CAyCjB"}
|
|
@@ -4,6 +4,7 @@ import { headsAreSame } from "../helpers/headsAreSame.js";
|
|
|
4
4
|
import { mergeArrays } from "../helpers/mergeArrays.js";
|
|
5
5
|
import { keyHash, headsHash } from "./keyHash.js";
|
|
6
6
|
import { chunkTypeFromKey } from "./chunkTypeFromKey.js";
|
|
7
|
+
import * as Uuid from "uuid";
|
|
7
8
|
/**
|
|
8
9
|
* The storage subsystem is responsible for saving and loading Automerge documents to and from
|
|
9
10
|
* storage adapter. It also provides a generic key/value storage interface for other uses.
|
|
@@ -21,6 +22,18 @@ export class StorageSubsystem {
|
|
|
21
22
|
constructor(storageAdapter) {
|
|
22
23
|
this.#storageAdapter = storageAdapter;
|
|
23
24
|
}
|
|
25
|
+
async id() {
|
|
26
|
+
let storedId = await this.#storageAdapter.load(["storage-adapter-id"]);
|
|
27
|
+
let id;
|
|
28
|
+
if (storedId) {
|
|
29
|
+
id = new TextDecoder().decode(storedId);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
id = Uuid.v4();
|
|
33
|
+
await this.#storageAdapter.save(["storage-adapter-id"], new TextEncoder().encode(id));
|
|
34
|
+
}
|
|
35
|
+
return id;
|
|
36
|
+
}
|
|
24
37
|
// ARBITRARY KEY/VALUE STORAGE
|
|
25
38
|
// The `load`, `save`, and `remove` methods are for generic key/value storage, as opposed to
|
|
26
39
|
// Automerge documents. For example, they're used by the LocalFirstAuthProvider to persist the
|
|
@@ -163,13 +176,13 @@ export class StorageSubsystem {
|
|
|
163
176
|
this.#chunkInfos.set(documentId, newChunkInfos);
|
|
164
177
|
this.#compacting = false;
|
|
165
178
|
}
|
|
166
|
-
async loadSyncState(documentId,
|
|
167
|
-
const key = [documentId, "sync-state",
|
|
179
|
+
async loadSyncState(documentId, storageId) {
|
|
180
|
+
const key = [documentId, "sync-state", storageId];
|
|
168
181
|
const loaded = await this.#storageAdapter.load(key);
|
|
169
182
|
return loaded ? A.decodeSyncState(loaded) : undefined;
|
|
170
183
|
}
|
|
171
|
-
async saveSyncState(documentId,
|
|
172
|
-
const key = [documentId, "sync-state",
|
|
184
|
+
async saveSyncState(documentId, storageId, syncState) {
|
|
185
|
+
const key = [documentId, "sync-state", storageId];
|
|
173
186
|
await this.#storageAdapter.save(key, A.encodeSyncState(syncState));
|
|
174
187
|
}
|
|
175
188
|
/**
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -34,4 +34,8 @@ export type ChunkType = "snapshot" | "incremental";
|
|
|
34
34
|
* should not assume any particular structure.
|
|
35
35
|
**/
|
|
36
36
|
export type StorageKey = string[];
|
|
37
|
+
/** A branded type for storage IDs */
|
|
38
|
+
export type StorageId = string & {
|
|
39
|
+
__storageId: true;
|
|
40
|
+
};
|
|
37
41
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAElD;;;;;;;;;;;;;;;;;IAiBI;AACJ,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;CAC7B,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,UAAU,CAAA;IACf,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAA;AAElD;;;;;;;;;;;;;;;;;IAiBI;AACJ,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,CAAA;AAEjC,qCAAqC;AACrC,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,WAAW,EAAE,IAAI,CAAA;CAAE,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Repo } from "../Repo.js";
|
|
2
|
-
import {
|
|
2
|
+
import { DocMessage } from "../network/messages.js";
|
|
3
3
|
import { DocumentId, PeerId } from "../types.js";
|
|
4
4
|
import { Synchronizer } from "./Synchronizer.js";
|
|
5
5
|
/** A CollectionSynchronizer is responsible for synchronizing a DocCollection with peers. */
|
|
@@ -11,7 +11,7 @@ export declare class CollectionSynchronizer extends Synchronizer {
|
|
|
11
11
|
* When we receive a sync message for a document we haven't got in memory, we
|
|
12
12
|
* register it with the repo and start synchronizing
|
|
13
13
|
*/
|
|
14
|
-
receiveMessage(message:
|
|
14
|
+
receiveMessage(message: DocMessage): Promise<void>;
|
|
15
15
|
/**
|
|
16
16
|
* Starts synchronizing the given document with all peers that we share it generously with.
|
|
17
17
|
*/
|
|
@@ -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,
|
|
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;IAmD9B;;;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"}
|
|
@@ -28,11 +28,15 @@ export class CollectionSynchronizer extends Synchronizer {
|
|
|
28
28
|
#initDocSynchronizer(handle) {
|
|
29
29
|
const docSynchronizer = new DocSynchronizer({
|
|
30
30
|
handle,
|
|
31
|
-
onLoadSyncState: peerId => {
|
|
31
|
+
onLoadSyncState: async (peerId) => {
|
|
32
32
|
if (!this.repo.storageSubsystem) {
|
|
33
|
-
return
|
|
33
|
+
return;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
const persistanceInfo = this.repo.persistanceInfoByPeerId[peerId];
|
|
36
|
+
if (!persistanceInfo || persistanceInfo.isEphemeral) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
return this.repo.storageSubsystem.loadSyncState(handle.documentId, persistanceInfo.storageId);
|
|
36
40
|
},
|
|
37
41
|
});
|
|
38
42
|
docSynchronizer.on("message", event => this.emit("message", event));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAG9C,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,WAAW,EAEZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,SAAS,CAAA;CAC9D;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAsBV,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyB9D,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;
|
|
1
|
+
{"version":3,"file":"DocSynchronizer.d.ts","sourceRoot":"","sources":["../../src/synchronizer/DocSynchronizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,2BAA2B,CAAA;AAG9C,OAAO,EACL,SAAS,EAKV,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,cAAc,EACd,WAAW,EAEZ,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAIhD,KAAK,kBAAkB,GAAG,SAAS,GAAG,KAAK,GAAG,aAAa,GAAG,OAAO,CAAA;AAOrE,UAAU,qBAAqB;IAC7B,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC1B,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,SAAS,CAAA;CAC9D;AAED;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,YAAY;;IAE/C,gBAAgB,SAAM;gBAsBV,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,qBAAqB;IAyB9D,IAAI,UAAU,uCAEb;IAED,IAAI,UAAU,qCAEb;IAyHD,OAAO,CAAC,MAAM,EAAE,MAAM;IAItB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE;IA+C3B,OAAO,CAAC,MAAM,EAAE,MAAM;IAKtB,cAAc,CAAC,OAAO,EAAE,WAAW;IAkBnC,uBAAuB,CAAC,OAAO,EAAE,gBAAgB;IAuBjD,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;CA8EzD"}
|
|
@@ -5,7 +5,6 @@ import { READY, REQUESTING, UNAVAILABLE, } from "../DocHandle.js";
|
|
|
5
5
|
import { isRequestMessage, } from "../network/messages.js";
|
|
6
6
|
import { Synchronizer } from "./Synchronizer.js";
|
|
7
7
|
import { throttle } from "../helpers/throttle.js";
|
|
8
|
-
import { headsAreSame } from "../helpers/headsAreSame.js";
|
|
9
8
|
/**
|
|
10
9
|
* DocSynchronizer takes a handle to an Automerge document, and receives & dispatches sync messages
|
|
11
10
|
* to bring it inline with all other peers' versions.
|
|
@@ -98,15 +97,7 @@ export class DocSynchronizer extends Synchronizer {
|
|
|
98
97
|
this.#syncStates[peerId] = syncState;
|
|
99
98
|
}
|
|
100
99
|
#setSyncState(peerId, syncState) {
|
|
101
|
-
const previousSyncState = this.#syncStates[peerId];
|
|
102
100
|
this.#syncStates[peerId] = syncState;
|
|
103
|
-
const haveTheirSyncedHeadsChanged = syncState.theirHeads &&
|
|
104
|
-
(!previousSyncState ||
|
|
105
|
-
!previousSyncState.theirHeads ||
|
|
106
|
-
!headsAreSame(previousSyncState.theirHeads, syncState.theirHeads));
|
|
107
|
-
if (haveTheirSyncedHeadsChanged) {
|
|
108
|
-
this.#handle.setRemoteHeads(peerId, syncState.theirHeads);
|
|
109
|
-
}
|
|
110
101
|
this.emit("sync-state", {
|
|
111
102
|
peerId,
|
|
112
103
|
syncState,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.1.0-alpha.1",
|
|
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>",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"http-server": "^14.1.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@automerge/automerge": "^2.1.
|
|
26
|
+
"@automerge/automerge": "^2.1.8-alpha.1",
|
|
27
27
|
"bs58check": "^3.0.1",
|
|
28
28
|
"cbor-x": "^1.3.0",
|
|
29
29
|
"debug": "^4.3.4",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"publishConfig": {
|
|
56
56
|
"access": "public"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "11805d698f860bd6ffb3ca028d3b57e718690b5a"
|
|
59
59
|
}
|
package/src/DocHandle.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { encode } from "./helpers/cbor.js"
|
|
|
19
19
|
import { headsAreSame } from "./helpers/headsAreSame.js"
|
|
20
20
|
import { withTimeout } from "./helpers/withTimeout.js"
|
|
21
21
|
import type { AutomergeUrl, DocumentId, PeerId } from "./types.js"
|
|
22
|
+
import { StorageId } from "./storage/types.js"
|
|
22
23
|
|
|
23
24
|
/** DocHandle is a wrapper around a single Automerge document that lets us
|
|
24
25
|
* listen for changes and notify the network and storage of new changes.
|
|
@@ -39,7 +40,7 @@ export class DocHandle<T> //
|
|
|
39
40
|
|
|
40
41
|
#machine: DocHandleXstateMachine<T>
|
|
41
42
|
#timeoutDelay: number
|
|
42
|
-
#remoteHeads: Record<
|
|
43
|
+
#remoteHeads: Record<StorageId, A.Heads> = {}
|
|
43
44
|
|
|
44
45
|
/** The URL of this document
|
|
45
46
|
*
|
|
@@ -71,9 +72,9 @@ export class DocHandle<T> //
|
|
|
71
72
|
* Internally we use a state machine to orchestrate document loading and/or syncing, in order to
|
|
72
73
|
* avoid requesting data we already have, or surfacing intermediate values to the consumer.
|
|
73
74
|
*
|
|
74
|
-
* ┌─────────────────────┬─────────TIMEOUT
|
|
75
|
-
* ┌───┴─────┐ ┌───┴────────┐ │
|
|
76
|
-
* ┌───────┐ ┌──FIND──┤ loading ├─REQUEST──►│ requesting ├─UPDATE──┐
|
|
75
|
+
* ┌─────────────────────┬─────────TIMEOUT────►┌─────────────┐
|
|
76
|
+
* ┌───┴─────┐ ┌───┴────────┐ │ unavailable │
|
|
77
|
+
* ┌───────┐ ┌──FIND──┤ loading ├─REQUEST──►│ requesting ├─UPDATE──┐ └─────────────┘
|
|
77
78
|
* │ idle ├──┤ └───┬─────┘ └────────────┘ │
|
|
78
79
|
* └───────┘ │ │ └─►┌────────┐
|
|
79
80
|
* │ └───────LOAD───────────────────────────────►│ ready │
|
|
@@ -111,7 +112,7 @@ export class DocHandle<T> //
|
|
|
111
112
|
after: [
|
|
112
113
|
{
|
|
113
114
|
delay: this.#timeoutDelay,
|
|
114
|
-
target:
|
|
115
|
+
target: UNAVAILABLE,
|
|
115
116
|
},
|
|
116
117
|
],
|
|
117
118
|
},
|
|
@@ -135,7 +136,7 @@ export class DocHandle<T> //
|
|
|
135
136
|
after: [
|
|
136
137
|
{
|
|
137
138
|
delay: this.#timeoutDelay,
|
|
138
|
-
target:
|
|
139
|
+
target: UNAVAILABLE,
|
|
139
140
|
},
|
|
140
141
|
],
|
|
141
142
|
},
|
|
@@ -146,9 +147,6 @@ export class DocHandle<T> //
|
|
|
146
147
|
DELETE: { actions: "onDelete", target: DELETED },
|
|
147
148
|
},
|
|
148
149
|
},
|
|
149
|
-
failed: {
|
|
150
|
-
type: "final",
|
|
151
|
-
},
|
|
152
150
|
deleted: {
|
|
153
151
|
type: "final",
|
|
154
152
|
},
|
|
@@ -240,7 +238,7 @@ export class DocHandle<T> //
|
|
|
240
238
|
return Promise.any(
|
|
241
239
|
awaitStates.map(state =>
|
|
242
240
|
waitFor(this.#machine, s => s.matches(state), {
|
|
243
|
-
timeout: this.#timeoutDelay *
|
|
241
|
+
timeout: this.#timeoutDelay * 2, // use a longer delay here so as not to race with other delays
|
|
244
242
|
})
|
|
245
243
|
)
|
|
246
244
|
)
|
|
@@ -294,7 +292,7 @@ export class DocHandle<T> //
|
|
|
294
292
|
// wait for the document to enter one of the desired states
|
|
295
293
|
await this.#statePromise(awaitStates)
|
|
296
294
|
} catch (error) {
|
|
297
|
-
// if we timed out (or the
|
|
295
|
+
// if we timed out (or have determined the document is currently unavailable), return undefined
|
|
298
296
|
return undefined
|
|
299
297
|
}
|
|
300
298
|
// Return the document
|
|
@@ -328,17 +326,17 @@ export class DocHandle<T> //
|
|
|
328
326
|
})
|
|
329
327
|
}
|
|
330
328
|
|
|
331
|
-
/** `setRemoteHeads` is called by the doc
|
|
329
|
+
/** `setRemoteHeads` is called by the repo either when a doc handle changes or we receive new remote heads
|
|
332
330
|
* @hidden
|
|
333
331
|
*/
|
|
334
|
-
setRemoteHeads(
|
|
335
|
-
this.#remoteHeads[
|
|
336
|
-
this.emit("remote-heads", {
|
|
332
|
+
setRemoteHeads(storageId: StorageId, heads: A.Heads) {
|
|
333
|
+
this.#remoteHeads[storageId] = heads
|
|
334
|
+
this.emit("remote-heads", { storageId, heads })
|
|
337
335
|
}
|
|
338
336
|
|
|
339
|
-
/** Returns the heads of the
|
|
340
|
-
getRemoteHeads(
|
|
341
|
-
return this.#remoteHeads[
|
|
337
|
+
/** Returns the heads of the storageId */
|
|
338
|
+
getRemoteHeads(storageId: StorageId): A.Heads | undefined {
|
|
339
|
+
return this.#remoteHeads[storageId]
|
|
342
340
|
}
|
|
343
341
|
|
|
344
342
|
/** `change` is called by the repo when the document is changed locally */
|
|
@@ -497,7 +495,7 @@ export interface DocHandleOutboundEphemeralMessagePayload<T> {
|
|
|
497
495
|
}
|
|
498
496
|
|
|
499
497
|
export interface DocHandleRemoteHeadsPayload {
|
|
500
|
-
|
|
498
|
+
storageId: StorageId
|
|
501
499
|
heads: A.Heads
|
|
502
500
|
}
|
|
503
501
|
|
|
@@ -538,8 +536,6 @@ export const HandleState = {
|
|
|
538
536
|
REQUESTING: "requesting",
|
|
539
537
|
/** The document is available */
|
|
540
538
|
READY: "ready",
|
|
541
|
-
/** We were unable to load or request the document for some reason */
|
|
542
|
-
FAILED: "failed",
|
|
543
539
|
/** The document has been deleted from the repo */
|
|
544
540
|
DELETED: "deleted",
|
|
545
541
|
/** The document was not available in storage or from any connected peers */
|
|
@@ -626,7 +622,6 @@ export const {
|
|
|
626
622
|
AWAITING_NETWORK,
|
|
627
623
|
REQUESTING,
|
|
628
624
|
READY,
|
|
629
|
-
FAILED,
|
|
630
625
|
DELETED,
|
|
631
626
|
UNAVAILABLE,
|
|
632
627
|
} = HandleState
|