@automerge/automerge-repo 1.0.2 → 1.0.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/DocHandle.d.ts +47 -5
- package/dist/DocHandle.d.ts.map +1 -1
- package/dist/DocHandle.js +40 -3
- package/dist/DocUrl.d.ts +3 -5
- package/dist/DocUrl.d.ts.map +1 -1
- package/dist/EphemeralData.d.ts +1 -0
- package/dist/EphemeralData.d.ts.map +1 -1
- package/dist/Repo.d.ts +25 -5
- package/dist/Repo.d.ts.map +1 -1
- package/dist/Repo.js +10 -0
- package/dist/index.d.ts +33 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -4
- package/dist/network/NetworkAdapter.d.ts +21 -0
- package/dist/network/NetworkAdapter.d.ts.map +1 -1
- package/dist/network/NetworkAdapter.js +7 -0
- package/dist/network/messages.d.ts +82 -7
- package/dist/network/messages.d.ts.map +1 -1
- package/dist/storage/StorageAdapter.d.ts +21 -0
- package/dist/storage/StorageAdapter.d.ts.map +1 -1
- package/dist/storage/StorageAdapter.js +6 -0
- package/dist/types.d.ts +12 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/DocHandle.ts +47 -4
- package/src/DocUrl.ts +1 -5
- package/src/EphemeralData.ts +1 -0
- package/src/Repo.ts +25 -4
- package/src/index.ts +44 -6
- package/src/network/NetworkAdapter.ts +21 -0
- package/src/network/messages.ts +105 -8
- package/src/storage/StorageAdapter.ts +21 -0
- package/src/types.ts +12 -4
- package/test/StorageSubsystem.test.ts +1 -1
- package/typedoc.json +5 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SessionId } from "../EphemeralData.js";
|
|
2
|
+
export { type SessionId } from "../EphemeralData.js";
|
|
2
3
|
import { DocumentId, PeerId } from "../types.js";
|
|
3
4
|
export declare function isValidMessage(message: NetworkAdapterMessage): message is SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
|
|
4
5
|
export declare function isDocumentUnavailableMessage(message: NetworkAdapterMessage): message is DocumentUnavailableMessage;
|
|
@@ -14,7 +15,20 @@ export interface SyncMessageContents {
|
|
|
14
15
|
targetId: PeerId;
|
|
15
16
|
documentId: DocumentId;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
+
/**
|
|
19
|
+
* A sync message for a particular document
|
|
20
|
+
*/
|
|
21
|
+
export type SyncMessage = {
|
|
22
|
+
/** The peer ID of the sender of this message */
|
|
23
|
+
senderId: PeerId;
|
|
24
|
+
type: "sync";
|
|
25
|
+
/** The automerge sync message */
|
|
26
|
+
data: Uint8Array;
|
|
27
|
+
/** The peer ID of the recipient of this message */
|
|
28
|
+
targetId: PeerId;
|
|
29
|
+
/** The document ID of the document this message is for */
|
|
30
|
+
documentId: DocumentId;
|
|
31
|
+
};
|
|
18
32
|
export interface EphemeralMessageEnvelope {
|
|
19
33
|
senderId: PeerId;
|
|
20
34
|
count: number;
|
|
@@ -26,32 +40,93 @@ export interface EphemeralMessageContents {
|
|
|
26
40
|
documentId: DocumentId;
|
|
27
41
|
data: Uint8Array;
|
|
28
42
|
}
|
|
29
|
-
|
|
43
|
+
/** An ephemeral message
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* Ephemeral messages are not persisted anywhere and have no particular
|
|
47
|
+
* structure. `automerge-repo` will gossip them around, in order to avoid
|
|
48
|
+
* eternal loops of ephemeral messages every message has a session ID, which
|
|
49
|
+
* is a random number generated by the sender at startup time, and a sequence
|
|
50
|
+
* number. The combination of these two things allows us to discard messages
|
|
51
|
+
* we have already seen.
|
|
52
|
+
* */
|
|
53
|
+
export type EphemeralMessage = {
|
|
54
|
+
/** The ID of the peer who sent this message */
|
|
55
|
+
senderId: PeerId;
|
|
56
|
+
/** A sequence number which must be incremented for each message sent by this peer */
|
|
57
|
+
count: number;
|
|
58
|
+
/** The ID of the session this message is part of. The sequence number for a given session always increases */
|
|
59
|
+
sessionId: SessionId;
|
|
60
|
+
type: "ephemeral";
|
|
61
|
+
/** The peer this message is for */
|
|
62
|
+
targetId: PeerId;
|
|
63
|
+
/** The document ID this message pertains to */
|
|
64
|
+
documentId: DocumentId;
|
|
65
|
+
/** The actual data of the message */
|
|
66
|
+
data: Uint8Array;
|
|
67
|
+
};
|
|
30
68
|
export interface DocumentUnavailableMessageContents {
|
|
31
69
|
type: "doc-unavailable";
|
|
32
70
|
documentId: DocumentId;
|
|
33
71
|
targetId: PeerId;
|
|
34
72
|
}
|
|
35
|
-
|
|
73
|
+
/** Sent by a {@link Repo} to indicate that it does not have the document and none of it's connected peers do either */
|
|
74
|
+
export type DocumentUnavailableMessage = {
|
|
75
|
+
/** The peer who sent this message */
|
|
76
|
+
senderId: PeerId;
|
|
77
|
+
type: "doc-unavailable";
|
|
78
|
+
/** The document which the peer claims it doesn't have */
|
|
79
|
+
documentId: DocumentId;
|
|
80
|
+
/** The peer this message is for */
|
|
81
|
+
targetId: PeerId;
|
|
82
|
+
};
|
|
36
83
|
export interface RequestMessageContents {
|
|
37
84
|
type: "request";
|
|
38
85
|
data: Uint8Array;
|
|
39
86
|
targetId: PeerId;
|
|
40
87
|
documentId: DocumentId;
|
|
41
88
|
}
|
|
42
|
-
|
|
89
|
+
/** Sent by a {@link Repo} to request a document from a peer
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* This is identical to a {@link SyncMessage} except that it is sent by a {@link Repo}
|
|
93
|
+
* as the initial sync message when asking the other peer if it has the document.
|
|
94
|
+
* */
|
|
95
|
+
export type RequestMessage = {
|
|
96
|
+
/** The peer who sent this message */
|
|
97
|
+
senderId: PeerId;
|
|
98
|
+
type: "request";
|
|
99
|
+
/** The initial automerge sync message */
|
|
100
|
+
data: Uint8Array;
|
|
101
|
+
/** The peer this message is for */
|
|
102
|
+
targetId: PeerId;
|
|
103
|
+
/** The document ID this message requests */
|
|
104
|
+
documentId: DocumentId;
|
|
105
|
+
};
|
|
43
106
|
export type MessageContents = SyncMessageContents | EphemeralMessageContents | RequestMessageContents | DocumentUnavailableMessageContents;
|
|
107
|
+
/** The type of messages that {@link Repo} sends and receive to {@link NetworkAdapter}s */
|
|
44
108
|
export type Message = SyncMessage | EphemeralMessage | RequestMessage | DocumentUnavailableMessage;
|
|
45
109
|
export type SynchronizerMessage = SyncMessage | RequestMessage | DocumentUnavailableMessage | EphemeralMessage;
|
|
46
|
-
|
|
110
|
+
/** Notify the network that we have arrived so everyone knows our peer ID */
|
|
111
|
+
export type ArriveMessage = {
|
|
112
|
+
/** Our peer ID */
|
|
47
113
|
senderId: PeerId;
|
|
48
114
|
type: "arrive";
|
|
49
115
|
};
|
|
50
|
-
|
|
116
|
+
/** Respond to an arriving peer with our peer ID */
|
|
117
|
+
export type WelcomeMessage = {
|
|
118
|
+
/** Our peer ID */
|
|
51
119
|
senderId: PeerId;
|
|
120
|
+
/** The ID of the peer who sent the {@link ArriveMessage} we are responding to */
|
|
52
121
|
targetId: PeerId;
|
|
53
122
|
type: "welcome";
|
|
54
123
|
};
|
|
124
|
+
/** The type of messages that {@link NetworkAdapter}s send and receive to each other
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* It is not _required_ that a {@link NetworkAdapter} use this message type.
|
|
128
|
+
* NetworkAdapters are free to use whatever message type makes sense for their
|
|
129
|
+
* transport. However, this type is a useful default.
|
|
130
|
+
* */
|
|
55
131
|
export type NetworkAdapterMessage = ArriveMessage | WelcomeMessage | Message;
|
|
56
|
-
export {};
|
|
57
132
|
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEhD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IACN,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,0BAA0B,CAU7B;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IAAI,0BAA0B,CAEvC;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IAAI,cAAc,CAE3B;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,IAAI,WAAW,CAExB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,qBAAqB,GAAG,eAAe,GAC/C,OAAO,IAAI,gBAAgB,GAAG,wBAAwB,CAExD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;CACvB;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/network/messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,33 @@
|
|
|
1
|
+
/** A storage adapter represents some way of storing binary data for a {@link Repo}
|
|
2
|
+
*
|
|
3
|
+
* @remarks
|
|
4
|
+
* `StorageAdapter`s are a little like a key/value store. The keys are arrays
|
|
5
|
+
* of strings ({@link StorageKey}) and the values are binary blobs.
|
|
6
|
+
*/
|
|
1
7
|
export declare abstract class StorageAdapter {
|
|
8
|
+
/** Load the single blob correspongind to `key` */
|
|
2
9
|
abstract load(key: StorageKey): Promise<Uint8Array | undefined>;
|
|
10
|
+
/** save the blod `data` to the key `key` */
|
|
3
11
|
abstract save(key: StorageKey, data: Uint8Array): Promise<void>;
|
|
12
|
+
/** remove the blob corresponding to `key` */
|
|
4
13
|
abstract remove(key: StorageKey): Promise<void>;
|
|
14
|
+
/** Load all blobs with keys that start with `keyPrefix` */
|
|
5
15
|
abstract loadRange(keyPrefix: StorageKey): Promise<{
|
|
6
16
|
key: StorageKey;
|
|
7
17
|
data: Uint8Array;
|
|
8
18
|
}[]>;
|
|
19
|
+
/** Remove all blobs with keys that start with `keyPrefix` */
|
|
9
20
|
abstract removeRange(keyPrefix: StorageKey): Promise<void>;
|
|
10
21
|
}
|
|
22
|
+
/** The type of keys for a {@link StorageAdapter}
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* Storage keys are arrays because they are hierarchical and the storage
|
|
26
|
+
* subsystem will need to be able to do range queries for all keys that
|
|
27
|
+
* have a particular prefix. For example, incremental changes for a given
|
|
28
|
+
* document might be stored under `[<documentId>, "incremental", <SHA256>]`.
|
|
29
|
+
* `StorageAdapter` implementations should not assume any particular structure
|
|
30
|
+
* though.
|
|
31
|
+
**/
|
|
11
32
|
export type StorageKey = string[];
|
|
12
33
|
//# sourceMappingURL=StorageAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StorageAdapter.d.ts","sourceRoot":"","sources":["../../src/storage/StorageAdapter.ts"],"names":[],"mappings":"AAAA,8BAAsB,cAAc;IAMlC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAC/D,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC;QAAC,GAAG,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAC,EAAE,CAAC;IACzF,QAAQ,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAC3D;AAED,MAAM,MAAO,UAAU,GAAG,MAAM,EAAE,CAAA"}
|
|
1
|
+
{"version":3,"file":"StorageAdapter.d.ts","sourceRoot":"","sources":["../../src/storage/StorageAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,8BAAsB,cAAc;IAMlC,kDAAkD;IAClD,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAC/D,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAC/D,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC;QAAC,GAAG,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAC,EAAE,CAAC;IACzF,6DAA6D;IAC7D,QAAQ,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CAC3D;AAED;;;;;;;;;IASI;AACJ,MAAM,MAAO,UAAU,GAAG,MAAM,EAAE,CAAA"}
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
/** A storage adapter represents some way of storing binary data for a {@link Repo}
|
|
2
|
+
*
|
|
3
|
+
* @remarks
|
|
4
|
+
* `StorageAdapter`s are a little like a key/value store. The keys are arrays
|
|
5
|
+
* of strings ({@link StorageKey}) and the values are binary blobs.
|
|
6
|
+
*/
|
|
1
7
|
export class StorageAdapter {
|
|
2
8
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
|
+
/** The ID of a document. Typically you should use a {@link AutomergeUrl} instead.
|
|
2
|
+
*/
|
|
1
3
|
export type DocumentId = string & {
|
|
2
4
|
__documentId: true;
|
|
3
5
|
};
|
|
6
|
+
/** A branded string representing a URL for a document
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* An automerge URL has the form `automerge:<base58 encoded string>`. This
|
|
10
|
+
* type is returned from various routines which validate a url.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
4
13
|
export type AutomergeUrl = string & {
|
|
5
14
|
__documentUrl: true;
|
|
6
15
|
};
|
|
16
|
+
/** A document ID as a Uint8Array instead of a bas58 encoded string. Typically you should use a {@link AutomergeUrl} instead.
|
|
17
|
+
*/
|
|
7
18
|
export type BinaryDocumentId = Uint8Array & {
|
|
8
19
|
__binaryDocumentId: true;
|
|
9
20
|
};
|
|
21
|
+
/** A branded type for peer IDs */
|
|
10
22
|
export type PeerId = string & {
|
|
11
23
|
__peerId: false;
|
|
12
24
|
};
|
|
13
|
-
export type DistributiveOmit<T, K extends keyof any> = T extends any ? Omit<T, K> : never;
|
|
14
25
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG;IAAE,YAAY,EAAE,IAAI,CAAA;CAAE,CAAA;AACxD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAAE,aAAa,EAAE,IAAI,CAAA;CAAE,CAAA;AAC3D,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG;IAAE,kBAAkB,EAAE,IAAI,CAAA;CAAE,CAAA;AAExE,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,KAAK,CAAA;CAAE,CAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;GACG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG;IAAE,YAAY,EAAE,IAAI,CAAA;CAAE,CAAA;AACxD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAAE,aAAa,EAAE,IAAI,CAAA;CAAE,CAAA;AAC3D;GACG;AACH,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG;IAAE,kBAAkB,EAAE,IAAI,CAAA;CAAE,CAAA;AAExE,kCAAkC;AAClC,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG;IAAE,QAAQ,EAAE,KAAK,CAAA;CAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automerge/automerge-repo",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A repository object to manage a collection of automerge documents",
|
|
5
5
|
"repository": "https://github.com/automerge/automerge-repo",
|
|
6
6
|
"author": "Peter van Hardenberg <pvh@pvh.ca>",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"publishConfig": {
|
|
66
66
|
"access": "public"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "4f3391cd33cd0cabfebde48dbd56749ddb6922da"
|
|
69
69
|
}
|
package/src/DocHandle.ts
CHANGED
|
@@ -21,7 +21,18 @@ import type { DocumentId, PeerId, AutomergeUrl } from "./types.js"
|
|
|
21
21
|
import { stringifyAutomergeUrl } from "./DocUrl.js"
|
|
22
22
|
import { encode } from "./helpers/cbor.js"
|
|
23
23
|
|
|
24
|
-
/** DocHandle is a wrapper around a single Automerge document that lets us
|
|
24
|
+
/** DocHandle is a wrapper around a single Automerge document that lets us
|
|
25
|
+
* listen for changes and notify the network and storage of new changes.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* A `DocHandle` represents a document which is being managed by a {@link Repo}.
|
|
29
|
+
* To obtain `DocHandle` use {@link Repo.find} or {@link Repo.create}.
|
|
30
|
+
*
|
|
31
|
+
* To modify the underlying document use either {@link DocHandle.change} or
|
|
32
|
+
* {@link DocHandle.changeAt}. These methods will notify the `Repo` that some
|
|
33
|
+
* change has occured and the `Repo` will save any new changes to the
|
|
34
|
+
* attached {@link StorageAdapter} and send sync messages to connected peers.
|
|
35
|
+
* */
|
|
25
36
|
export class DocHandle<T> //
|
|
26
37
|
extends EventEmitter<DocHandleEvents<T>>
|
|
27
38
|
{
|
|
@@ -30,10 +41,16 @@ export class DocHandle<T> //
|
|
|
30
41
|
#machine: DocHandleXstateMachine<T>
|
|
31
42
|
#timeoutDelay: number
|
|
32
43
|
|
|
44
|
+
/** The URL of this document
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* This can be used to request the document from an instance of {@link Repo}
|
|
48
|
+
*/
|
|
33
49
|
get url(): AutomergeUrl {
|
|
34
50
|
return stringifyAutomergeUrl({ documentId: this.documentId })
|
|
35
51
|
}
|
|
36
52
|
|
|
53
|
+
/** @hidden */
|
|
37
54
|
constructor(
|
|
38
55
|
public documentId: DocumentId,
|
|
39
56
|
{ isNew = false, timeoutDelay = 60_000 }: DocHandleOptions = {}
|
|
@@ -248,6 +265,7 @@ export class DocHandle<T> //
|
|
|
248
265
|
inState = (states: HandleState[]) =>
|
|
249
266
|
states.some(this.#machine?.getSnapshot().matches)
|
|
250
267
|
|
|
268
|
+
/** @hidden */
|
|
251
269
|
get state() {
|
|
252
270
|
return this.#machine?.getSnapshot().value
|
|
253
271
|
}
|
|
@@ -303,7 +321,9 @@ export class DocHandle<T> //
|
|
|
303
321
|
return this.#doc
|
|
304
322
|
}
|
|
305
323
|
|
|
306
|
-
/** `update` is called by the repo when we receive changes from the network
|
|
324
|
+
/** `update` is called by the repo when we receive changes from the network
|
|
325
|
+
* @hidden
|
|
326
|
+
* */
|
|
307
327
|
update(callback: (doc: A.Doc<T>) => A.Doc<T>) {
|
|
308
328
|
this.#machine.send(UPDATE, {
|
|
309
329
|
payload: { callback },
|
|
@@ -357,15 +377,19 @@ export class DocHandle<T> //
|
|
|
357
377
|
this.#machine.send(MARK_UNAVAILABLE)
|
|
358
378
|
}
|
|
359
379
|
|
|
360
|
-
/** `request` is called by the repo when the document is not found in storage
|
|
380
|
+
/** `request` is called by the repo when the document is not found in storage
|
|
381
|
+
* @hidden
|
|
382
|
+
* */
|
|
361
383
|
request() {
|
|
362
384
|
if (this.#state === LOADING) this.#machine.send(REQUEST)
|
|
363
385
|
}
|
|
364
386
|
|
|
387
|
+
/** @hidden */
|
|
365
388
|
awaitNetwork() {
|
|
366
389
|
if (this.#state === LOADING) this.#machine.send(AWAIT_NETWORK)
|
|
367
390
|
}
|
|
368
391
|
|
|
392
|
+
/** @hidden */
|
|
369
393
|
networkReady() {
|
|
370
394
|
if (this.#state === AWAITING_NETWORK) this.#machine.send(NETWORK_READY)
|
|
371
395
|
}
|
|
@@ -391,7 +415,8 @@ export class DocHandle<T> //
|
|
|
391
415
|
|
|
392
416
|
// WRAPPER CLASS TYPES
|
|
393
417
|
|
|
394
|
-
|
|
418
|
+
/** @hidden */
|
|
419
|
+
export interface DocHandleOptions {
|
|
395
420
|
isNew?: boolean
|
|
396
421
|
timeoutDelay?: number
|
|
397
422
|
}
|
|
@@ -411,10 +436,15 @@ export interface DocHandleDeletePayload<T> {
|
|
|
411
436
|
handle: DocHandle<T>
|
|
412
437
|
}
|
|
413
438
|
|
|
439
|
+
/** Emitted when a document has changed */
|
|
414
440
|
export interface DocHandleChangePayload<T> {
|
|
441
|
+
/** The hande which changed */
|
|
415
442
|
handle: DocHandle<T>
|
|
443
|
+
/** The value of the document after the change */
|
|
416
444
|
doc: A.Doc<T>
|
|
445
|
+
/** The patches representing the change that occurred */
|
|
417
446
|
patches: A.Patch[]
|
|
447
|
+
/** Information about the change */
|
|
418
448
|
patchInfo: A.PatchInfo<T>
|
|
419
449
|
}
|
|
420
450
|
|
|
@@ -444,14 +474,27 @@ export interface DocHandleEvents<T> {
|
|
|
444
474
|
|
|
445
475
|
// state
|
|
446
476
|
|
|
477
|
+
/**
|
|
478
|
+
* The state of a document handle
|
|
479
|
+
* @enum
|
|
480
|
+
*
|
|
481
|
+
*/
|
|
447
482
|
export const HandleState = {
|
|
483
|
+
/** The handle has been created but not yet loaded or requested */
|
|
448
484
|
IDLE: "idle",
|
|
485
|
+
/** We are waiting for storage to finish loading */
|
|
449
486
|
LOADING: "loading",
|
|
487
|
+
/** We are waiting for the network to be come ready */
|
|
450
488
|
AWAITING_NETWORK: "awaitingNetwork",
|
|
489
|
+
/** We are waiting for someone in the network to respond to a sync request */
|
|
451
490
|
REQUESTING: "requesting",
|
|
491
|
+
/** The document is available */
|
|
452
492
|
READY: "ready",
|
|
493
|
+
/** We were unable to load or request the document for some reason */
|
|
453
494
|
FAILED: "failed",
|
|
495
|
+
/** The document has been deleted from the repo */
|
|
454
496
|
DELETED: "deleted",
|
|
497
|
+
/** The document was not available in storage or from any connected peers */
|
|
455
498
|
UNAVAILABLE: "unavailable",
|
|
456
499
|
} as const
|
|
457
500
|
export type HandleState = (typeof HandleState)[keyof typeof HandleState]
|
package/src/DocUrl.ts
CHANGED
|
@@ -20,10 +20,6 @@ export const parseAutomergeUrl = (url: AutomergeUrl) => {
|
|
|
20
20
|
return { binaryDocumentId, documentId }
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
interface StringifyAutomergeUrlOptions {
|
|
24
|
-
documentId: DocumentId | BinaryDocumentId
|
|
25
|
-
}
|
|
26
|
-
|
|
27
23
|
/**
|
|
28
24
|
* Given a documentId in either canonical form, return an Automerge URL
|
|
29
25
|
* Throws on invalid input.
|
|
@@ -33,7 +29,7 @@ interface StringifyAutomergeUrlOptions {
|
|
|
33
29
|
*/
|
|
34
30
|
export const stringifyAutomergeUrl = ({
|
|
35
31
|
documentId,
|
|
36
|
-
}:
|
|
32
|
+
}: {documentId: DocumentId | BinaryDocumentId}): AutomergeUrl => {
|
|
37
33
|
if (documentId instanceof Uint8Array)
|
|
38
34
|
return (urlPrefix +
|
|
39
35
|
binaryToDocumentId(documentId as BinaryDocumentId)) as AutomergeUrl
|
package/src/EphemeralData.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { DocumentId, PeerId } from "./index.js"
|
|
|
2
2
|
import { EphemeralMessageContents } from "./network/messages.js"
|
|
3
3
|
|
|
4
4
|
// types
|
|
5
|
+
/** A randomly generated string created when the {@link Repo} starts up */
|
|
5
6
|
export type SessionId = string & { __SessionId: false }
|
|
6
7
|
|
|
7
8
|
export interface EphemeralDataPayload {
|
package/src/Repo.ts
CHANGED
|
@@ -18,14 +18,24 @@ import { EventEmitter } from "eventemitter3"
|
|
|
18
18
|
import bs58check from "bs58check"
|
|
19
19
|
|
|
20
20
|
/** A Repo is a collection of documents with networking, syncing, and storage capabilities. */
|
|
21
|
-
|
|
21
|
+
/** The `Repo` is the main entry point of this library
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* To construct a `Repo` you will need an {@link StorageAdapter} and one or
|
|
25
|
+
* more {@link NetworkAdapter}s. Once you have a `Repo` you can use it to
|
|
26
|
+
* obtain {@link DocHandle}s.
|
|
27
|
+
*/
|
|
28
|
+
export class Repo extends EventEmitter<RepoEvents> {
|
|
22
29
|
#log: debug.Debugger
|
|
23
30
|
|
|
31
|
+
/** @hidden */
|
|
24
32
|
networkSubsystem: NetworkSubsystem
|
|
33
|
+
/** @hidden */
|
|
25
34
|
storageSubsystem?: StorageSubsystem
|
|
26
35
|
#handleCache: Record<DocumentId, DocHandle<any>> = {}
|
|
27
36
|
|
|
28
37
|
/** By default, we share generously with all peers. */
|
|
38
|
+
/** @hidden */
|
|
29
39
|
sharePolicy: SharePolicy = async () => true
|
|
30
40
|
|
|
31
41
|
constructor({ storage, network, peerId, sharePolicy }: RepoConfig) {
|
|
@@ -257,23 +267,34 @@ export interface RepoConfig {
|
|
|
257
267
|
sharePolicy?: SharePolicy
|
|
258
268
|
}
|
|
259
269
|
|
|
270
|
+
/** A function that determines whether we should share a document with a peer
|
|
271
|
+
*
|
|
272
|
+
* @remarks
|
|
273
|
+
* This function is called by the {@link Repo} every time a new document is created
|
|
274
|
+
* or discovered (such as when another peer starts syncing with us). If this
|
|
275
|
+
* function returns `true` then the {@link Repo} will begin sharing the new
|
|
276
|
+
* document with the peer given by `peerId`.
|
|
277
|
+
* */
|
|
260
278
|
export type SharePolicy = (
|
|
261
279
|
peerId: PeerId,
|
|
262
280
|
documentId?: DocumentId
|
|
263
281
|
) => Promise<boolean>
|
|
264
282
|
|
|
265
283
|
// events & payloads
|
|
266
|
-
interface
|
|
284
|
+
export interface RepoEvents {
|
|
285
|
+
/** A new document was created or discovered */
|
|
267
286
|
document: (arg: DocumentPayload) => void
|
|
287
|
+
/** A document was deleted */
|
|
268
288
|
"delete-document": (arg: DeleteDocumentPayload) => void
|
|
289
|
+
/** A document was marked as unavailable (we don't have it and none of our peers have it) */
|
|
269
290
|
"unavailable-document": (arg: DeleteDocumentPayload) => void
|
|
270
291
|
}
|
|
271
292
|
|
|
272
|
-
interface DocumentPayload {
|
|
293
|
+
export interface DocumentPayload {
|
|
273
294
|
handle: DocHandle<any>
|
|
274
295
|
isNew: boolean
|
|
275
296
|
}
|
|
276
297
|
|
|
277
|
-
interface DeleteDocumentPayload {
|
|
298
|
+
export interface DeleteDocumentPayload {
|
|
278
299
|
documentId: DocumentId
|
|
279
300
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* The [`automerge`](https://www.npmjs.com/package/@automerge/automerge) CRDT
|
|
5
|
+
* provides a core CRDT data structure and an implementation of a storage
|
|
6
|
+
* format and sync protocol but doesn't provide the plumbing to use these tools
|
|
7
|
+
* in a JS application. `automerge-repo` provides the plumbing.
|
|
8
|
+
*
|
|
9
|
+
* The main entry point is the {@link Repo} class, which you instantiate with
|
|
10
|
+
* a {@link StorageAdapter} and zero or more {@link NetworkAdapter}s. Once you
|
|
11
|
+
* have a repo you can use it to create {@link DocHandle}s. {@link DocHandle}s
|
|
12
|
+
* are a reference to a document, identified by a {@link AutomergeUrl}, a place to
|
|
13
|
+
* listen for changes to the document, and to make new changes.
|
|
14
|
+
*
|
|
15
|
+
* A typical example of how to use this library then might look like this:
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { Repo } from "@automerge/automerge-repo";
|
|
19
|
+
*
|
|
20
|
+
* const repo = new Repo({
|
|
21
|
+
* storage: <storage adapter>,
|
|
22
|
+
* network: [<network adapter>, <network adapter>]
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* const handle = repo.create
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
export { DocHandle, type HandleState, type DocHandleOptions, type DocHandleEvents } from "./DocHandle.js"
|
|
30
|
+
export type {
|
|
31
|
+
DocHandleChangePayload,
|
|
32
|
+
DocHandleDeletePayload,
|
|
33
|
+
DocHandleEphemeralMessagePayload,
|
|
34
|
+
DocHandleOutboundEphemeralMessagePayload,
|
|
35
|
+
DocHandleEncodedChangePayload,
|
|
36
|
+
} from "./DocHandle.js"
|
|
3
37
|
export { NetworkAdapter } from "./network/NetworkAdapter.js"
|
|
4
38
|
export type {
|
|
5
39
|
OpenPayload,
|
|
6
40
|
PeerCandidatePayload,
|
|
7
41
|
PeerDisconnectedPayload,
|
|
42
|
+
NetworkAdapterEvents,
|
|
8
43
|
} from "./network/NetworkAdapter.js"
|
|
9
44
|
|
|
10
45
|
// This is a bit confusing right now, but:
|
|
@@ -13,17 +48,19 @@ export type {
|
|
|
13
48
|
// and Message is (as of this writing) a union type for EphmeralMessage and SyncMessage
|
|
14
49
|
export type {
|
|
15
50
|
Message,
|
|
51
|
+
ArriveMessage,
|
|
52
|
+
WelcomeMessage,
|
|
16
53
|
NetworkAdapterMessage,
|
|
17
54
|
EphemeralMessage,
|
|
55
|
+
RequestMessage,
|
|
56
|
+
DocumentUnavailableMessage,
|
|
18
57
|
SyncMessage,
|
|
58
|
+
SessionId,
|
|
19
59
|
} from "./network/messages.js"
|
|
20
60
|
export { isValidMessage } from "./network/messages.js"
|
|
21
61
|
|
|
22
|
-
export {
|
|
23
|
-
export { Repo, type SharePolicy } from "./Repo.js"
|
|
62
|
+
export { Repo, type SharePolicy, type RepoConfig, type RepoEvents, type DeleteDocumentPayload, type DocumentPayload } from "./Repo.js"
|
|
24
63
|
export { StorageAdapter, type StorageKey } from "./storage/StorageAdapter.js"
|
|
25
|
-
export { StorageSubsystem } from "./storage/StorageSubsystem.js"
|
|
26
|
-
export { CollectionSynchronizer } from "./synchronizer/CollectionSynchronizer.js"
|
|
27
64
|
export {
|
|
28
65
|
parseAutomergeUrl,
|
|
29
66
|
isValidAutomergeUrl,
|
|
@@ -31,4 +68,5 @@ export {
|
|
|
31
68
|
} from "./DocUrl.js"
|
|
32
69
|
export * from "./types.js"
|
|
33
70
|
|
|
71
|
+
/** @hidden **/
|
|
34
72
|
export * as cbor from "./helpers/cbor.js"
|
|
@@ -2,23 +2,44 @@ import { EventEmitter } from "eventemitter3"
|
|
|
2
2
|
import { PeerId } from "../types.js"
|
|
3
3
|
import { Message } from "./messages.js"
|
|
4
4
|
|
|
5
|
+
/** An interface representing some way to connect to other peers
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* The {@link Repo} uses one or more `NetworkAdapter`s to connect to other peers.
|
|
9
|
+
* Because the network may take some time to be ready the {@link Repo} will wait
|
|
10
|
+
* until the adapter emits a `ready` event before it starts trying to use it
|
|
11
|
+
*/
|
|
5
12
|
export abstract class NetworkAdapter extends EventEmitter<NetworkAdapterEvents> {
|
|
6
13
|
peerId?: PeerId // hmmm, maybe not
|
|
7
14
|
|
|
15
|
+
/** Called by the {@link Repo} to start the connection process
|
|
16
|
+
*
|
|
17
|
+
* @argument peerId - the peerId of this repo
|
|
18
|
+
*/
|
|
8
19
|
abstract connect(peerId: PeerId): void
|
|
9
20
|
|
|
21
|
+
/** Called by the {@link Repo} to send a message to a peer
|
|
22
|
+
*
|
|
23
|
+
* @argument message - the message to send
|
|
24
|
+
*/
|
|
10
25
|
abstract send(message: Message): void
|
|
11
26
|
|
|
27
|
+
/** Called by the {@link Repo} to disconnect from the network */
|
|
12
28
|
abstract disconnect(): void
|
|
13
29
|
}
|
|
14
30
|
|
|
15
31
|
// events & payloads
|
|
16
32
|
|
|
17
33
|
export interface NetworkAdapterEvents {
|
|
34
|
+
/** Emitted when the network is ready to be used */
|
|
18
35
|
ready: (payload: OpenPayload) => void
|
|
36
|
+
/** Emitted when the network is closed */
|
|
19
37
|
close: () => void
|
|
38
|
+
/** Emitted when the network adapter learns about a new peer */
|
|
20
39
|
"peer-candidate": (payload: PeerCandidatePayload) => void
|
|
40
|
+
/** Emitted when the network adapter learns that a peer has disconnected */
|
|
21
41
|
"peer-disconnected": (payload: PeerDisconnectedPayload) => void
|
|
42
|
+
/** Emitted when the network adapter receives a message from a peer */
|
|
22
43
|
message: (payload: Message) => void
|
|
23
44
|
}
|
|
24
45
|
|