@automerge/automerge-repo 2.5.2-alpha.0 → 2.5.2-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.
@@ -0,0 +1,2 @@
1
+ export declare function unique<T>(items: T[]): T[];
2
+ //# sourceMappingURL=array.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../../src/helpers/array.ts"],"names":[],"mappings":"AAAA,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAEnC"}
@@ -0,0 +1,3 @@
1
+ export function unique(items) {
2
+ return Array.from(new Set(items));
3
+ }
package/dist/index.d.ts CHANGED
@@ -28,7 +28,9 @@
28
28
  export { DocHandle } from "./DocHandle.js";
29
29
  export { isValidAutomergeUrl, isValidDocumentId, parseAutomergeUrl, stringifyAutomergeUrl, interpretAsDocumentId, documentIdToBinary, generateAutomergeUrl, encodeHeads, decodeHeads, } from "./AutomergeUrl.js";
30
30
  export { Repo } from "./Repo.js";
31
- export { Presence, PeerPresenceView, PeerState, PresenceConfig, UserId, DeviceId, } from "./Presence.js";
31
+ export { Presence } from "./presence/Presence.js";
32
+ export { PeerStateView } from "./presence/PeerStateView.js";
33
+ export type { PeerState, PresenceState, PresenceConfig, UserId, DeviceId, } from "./presence/types.js";
32
34
  export { NetworkAdapter } from "./network/NetworkAdapter.js";
33
35
  export type { NetworkAdapterInterface } from "./network/NetworkAdapterInterface.js";
34
36
  export { isRepoMessage } from "./network/messages.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -28,7 +28,8 @@
28
28
  export { DocHandle } from "./DocHandle.js";
29
29
  export { isValidAutomergeUrl, isValidDocumentId, parseAutomergeUrl, stringifyAutomergeUrl, interpretAsDocumentId, documentIdToBinary, generateAutomergeUrl, encodeHeads, decodeHeads, } from "./AutomergeUrl.js";
30
30
  export { Repo } from "./Repo.js";
31
- export { Presence, PeerPresenceView, } from "./Presence.js";
31
+ export { Presence } from "./presence/Presence.js";
32
+ export { PeerStateView } from "./presence/PeerStateView.js";
32
33
  export { NetworkAdapter } from "./network/NetworkAdapter.js";
33
34
  export { isRepoMessage } from "./network/messages.js";
34
35
  export { StorageAdapter } from "./storage/StorageAdapter.js";
@@ -0,0 +1,50 @@
1
+ import { PeerId } from "../types.js";
2
+ import { PeerStateView } from "./PeerStateView.js";
3
+ import { DeviceId, PresenceState, UserId } from "./types.js";
4
+ export declare class PeerPresenceInfo<State extends PresenceState> {
5
+ #private;
6
+ readonly ttl: number;
7
+ /**
8
+ * Build a new peer presence state.
9
+ *
10
+ * @param ttl in milliseconds - peers with no activity within this timeframe
11
+ * are forgotten when {@link prune} is called.
12
+ */
13
+ constructor(ttl: number);
14
+ has(peerId: PeerId): boolean;
15
+ /**
16
+ * Record that we've seen the given peer recently.
17
+ *
18
+ * @param peerId
19
+ */
20
+ markSeen(peerId: PeerId): void;
21
+ /**
22
+ * Record a state update for the given peer. Note that existing state is not
23
+ * overwritten.
24
+ *
25
+ * @param peerId
26
+ * @param value
27
+ */
28
+ update({ peerId, deviceId, userId, value, }: {
29
+ peerId: PeerId;
30
+ deviceId?: DeviceId;
31
+ userId?: UserId;
32
+ value: Partial<State>;
33
+ }): void;
34
+ /**
35
+ * Forget the given peer.
36
+ *
37
+ * @param peerId
38
+ */
39
+ delete(peerId: PeerId): void;
40
+ /**
41
+ * Prune all peers that have not been seen since the configured ttl has
42
+ * elapsed.
43
+ */
44
+ prune(): void;
45
+ /**
46
+ * Get a snapshot of the current peer states
47
+ */
48
+ get states(): PeerStateView<State>;
49
+ }
50
+ //# sourceMappingURL=PeerPresenceInfo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PeerPresenceInfo.d.ts","sourceRoot":"","sources":["../../src/presence/PeerPresenceInfo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE5D,qBAAa,gBAAgB,CAAC,KAAK,SAAS,aAAa;;IAS3C,QAAQ,CAAC,GAAG,EAAE,MAAM;IANhC;;;;;OAKG;gBACkB,GAAG,EAAE,MAAM;IAEhC,GAAG,CAAC,MAAM,EAAE,MAAM;IAIlB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM;IAUvB;;;;;;OAMG;IACH,MAAM,CAAC,EACL,MAAM,EACN,QAAQ,EACR,MAAM,EACN,KAAK,GACN,EAAE;QACD,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,QAAQ,CAAA;QACnB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;KACtB;IAoBD;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM;IAUrB;;;OAGG;IACH,KAAK;IAWL;;OAEG;IACH,IAAI,MAAM,yBAET;CACF"}
@@ -0,0 +1,83 @@
1
+ import { PeerStateView } from "./PeerStateView.js";
2
+ export class PeerPresenceInfo {
3
+ ttl;
4
+ #peerStates = new PeerStateView({});
5
+ /**
6
+ * Build a new peer presence state.
7
+ *
8
+ * @param ttl in milliseconds - peers with no activity within this timeframe
9
+ * are forgotten when {@link prune} is called.
10
+ */
11
+ constructor(ttl) {
12
+ this.ttl = ttl;
13
+ }
14
+ has(peerId) {
15
+ return peerId in this.#peerStates.value;
16
+ }
17
+ /**
18
+ * Record that we've seen the given peer recently.
19
+ *
20
+ * @param peerId
21
+ */
22
+ markSeen(peerId) {
23
+ this.#peerStates = new PeerStateView({
24
+ ...this.#peerStates.value,
25
+ [peerId]: {
26
+ ...this.#peerStates.value[peerId],
27
+ lastSeen: Date.now(),
28
+ },
29
+ });
30
+ }
31
+ /**
32
+ * Record a state update for the given peer. Note that existing state is not
33
+ * overwritten.
34
+ *
35
+ * @param peerId
36
+ * @param value
37
+ */
38
+ update({ peerId, deviceId, userId, value, }) {
39
+ const peerState = this.#peerStates.value[peerId];
40
+ const existingState = peerState?.value ?? {};
41
+ const now = Date.now();
42
+ this.#peerStates = new PeerStateView({
43
+ ...this.#peerStates.value,
44
+ [peerId]: {
45
+ peerId,
46
+ deviceId,
47
+ userId,
48
+ lastActiveAt: now,
49
+ lastUpdateAt: now,
50
+ value: {
51
+ ...existingState,
52
+ ...value,
53
+ },
54
+ },
55
+ });
56
+ }
57
+ /**
58
+ * Forget the given peer.
59
+ *
60
+ * @param peerId
61
+ */
62
+ delete(peerId) {
63
+ this.#peerStates = new PeerStateView(Object.fromEntries(Object.entries(this.#peerStates.value).filter(([existingId]) => {
64
+ return existingId != peerId;
65
+ })));
66
+ }
67
+ /**
68
+ * Prune all peers that have not been seen since the configured ttl has
69
+ * elapsed.
70
+ */
71
+ prune() {
72
+ const threshold = Date.now() - this.ttl;
73
+ this.#peerStates = new PeerStateView(Object.fromEntries(Object.entries(this.#peerStates).filter(([, state]) => {
74
+ return state.lastActiveAt >= threshold;
75
+ })));
76
+ }
77
+ /**
78
+ * Get a snapshot of the current peer states
79
+ */
80
+ get states() {
81
+ return this.#peerStates;
82
+ }
83
+ }
@@ -0,0 +1,69 @@
1
+ import { PeerId } from "../types.js";
2
+ import { DeviceId, PeerStatesValue, PresenceState, UserId } from "./types.js";
3
+ export declare class PeerStateView<State extends PresenceState> {
4
+ readonly value: PeerStatesValue<State>;
5
+ constructor(value: PeerStatesValue<State>);
6
+ /**
7
+ * Get all users.
8
+ *
9
+ * @returns Array of user presence {@link State}s
10
+ */
11
+ get users(): (import("./types.js").PeerState<State> | undefined)[];
12
+ /**
13
+ * Get all devices.
14
+ *
15
+ * @returns Array of device presence {@link State}s
16
+ */
17
+ get devices(): (import("./types.js").PeerState<State> | undefined)[];
18
+ /**
19
+ * Get all peers.
20
+ *
21
+ * @returns Array of peer presence {@link State}s
22
+ */
23
+ get peers(): import("./types.js").PeerState<State>[];
24
+ /**
25
+ * Get all peer ids for this user.
26
+ *
27
+ * @param userId
28
+ * @returns Array of peer ids for this user
29
+ */
30
+ getUserPeers(userId: UserId): PeerId[];
31
+ /**
32
+ * Get all peers for this device.
33
+ *
34
+ * @param deviceId
35
+ * @returns Array of peer ids for this device
36
+ */
37
+ getDevicePeers(deviceId: DeviceId): PeerId[];
38
+ /**
39
+ * Return the most-recently-seen peer from this group.
40
+ *
41
+ * @param peers
42
+ * @returns id of most recently seen peer
43
+ */
44
+ getLastSeenPeer(peers: PeerId[]): PeerId | undefined;
45
+ /**
46
+ * Return the peer from this group that sent a state update most recently
47
+ *
48
+ * @param peers
49
+ * @returns id of most recently seen peer
50
+ */
51
+ getLastActivePeer(peers: PeerId[]): PeerId | undefined;
52
+ /**
53
+ * Get current ephemeral state value for this user's most-recently-active
54
+ * peer.
55
+ *
56
+ * @param userId
57
+ * @returns user's {@link State}
58
+ */
59
+ getUserState(userId: UserId): import("./types.js").PeerState<State> | undefined;
60
+ /**
61
+ * Get current ephemeral state value for this device's most-recently-active
62
+ * peer.
63
+ *
64
+ * @param deviceId
65
+ * @returns device's {@link State}
66
+ */
67
+ getDeviceState(deviceId: DeviceId): import("./types.js").PeerState<State> | undefined;
68
+ }
69
+ //# sourceMappingURL=PeerStateView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PeerStateView.d.ts","sourceRoot":"","sources":["../../src/presence/PeerStateView.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAE7E,qBAAa,aAAa,CAAC,KAAK,SAAS,aAAa;IACpD,QAAQ,CAAC,KAAK,yBAAA;gBAEF,KAAK,EAAE,eAAe,CAAC,KAAK,CAAC;IAIzC;;;;OAIG;IACH,IAAI,KAAK,0DAKR;IAED;;;;OAIG;IACH,IAAI,OAAO,0DAKV;IAED;;;;OAIG;IACH,IAAI,KAAK,4CAER;IAED;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM;IAM3B;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,QAAQ;IAMjC;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE;IAiB/B;;;;;OAKG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE;IAiBjC;;;;;;OAMG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM;IAa3B;;;;;;OAMG;IACH,cAAc,CAAC,QAAQ,EAAE,QAAQ;CAYlC"}
@@ -0,0 +1,131 @@
1
+ import { unique } from "../helpers/array.js";
2
+ export class PeerStateView {
3
+ value;
4
+ constructor(value) {
5
+ this.value = value;
6
+ }
7
+ /**
8
+ * Get all users.
9
+ *
10
+ * @returns Array of user presence {@link State}s
11
+ */
12
+ get users() {
13
+ const userIds = unique(Object.values(this.value).map(peerState => peerState.userId));
14
+ return userIds.map(u => this.getUserState(u));
15
+ }
16
+ /**
17
+ * Get all devices.
18
+ *
19
+ * @returns Array of device presence {@link State}s
20
+ */
21
+ get devices() {
22
+ const deviceIds = unique(Object.values(this.value).map(peerState => peerState.deviceId));
23
+ return deviceIds.map(d => this.getDeviceState(d));
24
+ }
25
+ /**
26
+ * Get all peers.
27
+ *
28
+ * @returns Array of peer presence {@link State}s
29
+ */
30
+ get peers() {
31
+ return Object.values(this.value);
32
+ }
33
+ /**
34
+ * Get all peer ids for this user.
35
+ *
36
+ * @param userId
37
+ * @returns Array of peer ids for this user
38
+ */
39
+ getUserPeers(userId) {
40
+ return Object.values(this.value)
41
+ .filter(peerState => peerState.userId === userId)
42
+ .map(peerState => peerState.peerId);
43
+ }
44
+ /**
45
+ * Get all peers for this device.
46
+ *
47
+ * @param deviceId
48
+ * @returns Array of peer ids for this device
49
+ */
50
+ getDevicePeers(deviceId) {
51
+ return Object.values(this.value)
52
+ .filter(peerState => peerState.deviceId === deviceId)
53
+ .map(peerState => peerState.peerId);
54
+ }
55
+ /**
56
+ * Return the most-recently-seen peer from this group.
57
+ *
58
+ * @param peers
59
+ * @returns id of most recently seen peer
60
+ */
61
+ getLastSeenPeer(peers) {
62
+ let freshestLastSeenAt;
63
+ return peers.reduce((freshest, curr) => {
64
+ const lastSeenAt = this.value[curr]?.lastActiveAt;
65
+ if (!lastSeenAt) {
66
+ return freshest;
67
+ }
68
+ if (!freshest || lastSeenAt > freshestLastSeenAt) {
69
+ freshestLastSeenAt = lastSeenAt;
70
+ return curr;
71
+ }
72
+ return freshest;
73
+ }, undefined);
74
+ }
75
+ /**
76
+ * Return the peer from this group that sent a state update most recently
77
+ *
78
+ * @param peers
79
+ * @returns id of most recently seen peer
80
+ */
81
+ getLastActivePeer(peers) {
82
+ let freshestLastActiveAt;
83
+ return peers.reduce((freshest, curr) => {
84
+ const lastActiveAt = this.value[curr]?.lastActiveAt;
85
+ if (!lastActiveAt) {
86
+ return freshest;
87
+ }
88
+ if (!freshest || lastActiveAt > freshestLastActiveAt) {
89
+ freshestLastActiveAt = lastActiveAt;
90
+ return curr;
91
+ }
92
+ return freshest;
93
+ }, undefined);
94
+ }
95
+ /**
96
+ * Get current ephemeral state value for this user's most-recently-active
97
+ * peer.
98
+ *
99
+ * @param userId
100
+ * @returns user's {@link State}
101
+ */
102
+ getUserState(userId) {
103
+ const peers = this.getUserPeers(userId);
104
+ if (!peers) {
105
+ return undefined;
106
+ }
107
+ const peer = this.getLastActivePeer(peers);
108
+ if (!peer) {
109
+ return undefined;
110
+ }
111
+ return this.value[peer];
112
+ }
113
+ /**
114
+ * Get current ephemeral state value for this device's most-recently-active
115
+ * peer.
116
+ *
117
+ * @param deviceId
118
+ * @returns device's {@link State}
119
+ */
120
+ getDeviceState(deviceId) {
121
+ const peers = this.getDevicePeers(deviceId);
122
+ if (!peers) {
123
+ return undefined;
124
+ }
125
+ const peer = this.getLastActivePeer(peers);
126
+ if (!peer) {
127
+ return undefined;
128
+ }
129
+ return this.value[peer];
130
+ }
131
+ }
@@ -0,0 +1,81 @@
1
+ import { EventEmitter } from "eventemitter3";
2
+ import { DocHandle } from "../DocHandle.js";
3
+ import { DeviceId, PresenceConfig, PresenceEvents, PresenceState, UserId } from "./types.js";
4
+ /**
5
+ * Presence encapsulates ephemeral state communication for a specific doc
6
+ * handle. It tracks caller-provided local state and broadcasts that state to
7
+ * all peers. It sends periodic heartbeats when there are no state updates.
8
+ *
9
+ * It also tracks ephemeral state broadcast by peers and emits events when peers
10
+ * send ephemeral state updates (see {@link PresenceEvents}).
11
+ *
12
+ * Presence starts out in an inactive state. Call {@link start} and {@link stop}
13
+ * to activate and deactivate it.
14
+ */
15
+ export declare class Presence<State extends PresenceState, DocType = any> extends EventEmitter<PresenceEvents> {
16
+ #private;
17
+ readonly deviceId?: DeviceId;
18
+ readonly userId?: UserId;
19
+ /**
20
+ * Create a new Presence to share ephemeral state with peers.
21
+ *
22
+ * @param config see {@link PresenceConfig}
23
+ * @returns
24
+ */
25
+ constructor({ handle, deviceId, userId, }: {
26
+ handle: DocHandle<DocType>;
27
+ /** Our device id (like userId, this is unverified; peers can send anything) */
28
+ deviceId?: DeviceId;
29
+ /** Our user id (this is unverified; peers can send anything) */
30
+ userId?: UserId;
31
+ });
32
+ /**
33
+ * Start listening to ephemeral messages on the handle, broadcast initial
34
+ * state to peers, and start sending heartbeats.
35
+ */
36
+ start({ initialState, heartbeatMs, peerTtlMs }: PresenceConfig<State>): void;
37
+ /**
38
+ * Return a view of current peer states.
39
+ */
40
+ getPeerStates(): import("./PeerStateView.js").PeerStateView<State>;
41
+ /**
42
+ * Return a view of current local state.
43
+ */
44
+ getLocalState(): State;
45
+ /**
46
+ * Update state for the specific channel, and broadcast new state to all
47
+ * peers.
48
+ *
49
+ * @param channel
50
+ * @param value
51
+ */
52
+ broadcast<Channel extends keyof State>(channel: Channel, value: State[Channel]): void;
53
+ /**
54
+ * Whether this Presence is currently active. See
55
+ * {@link start} and {@link stop}.
56
+ */
57
+ get running(): boolean;
58
+ /**
59
+ * Stop this Presence: broadcast a "goodbye" message (when received, other
60
+ * peers will immediately forget the sender), stop sending heartbeats, and
61
+ * stop listening to ephemeral-messages broadcast from peers.
62
+ *
63
+ * This can be used with browser events like
64
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event | "pagehide"}
65
+ * or
66
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event | "visibilitychange"}
67
+ * to stop sending and receiving updates when not active.
68
+ */
69
+ stop(): void;
70
+ private announce;
71
+ private broadcastLocalState;
72
+ private broadcastChannelState;
73
+ private resetHeartbeats;
74
+ private doBroadcast;
75
+ private send;
76
+ private startHeartbeats;
77
+ private stopHeartbeats;
78
+ private startPruningPeers;
79
+ private stopPruningPeers;
80
+ }
81
+ //# sourceMappingURL=Presence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Presence.d.ts","sourceRoot":"","sources":["../../src/presence/Presence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAE5C,OAAO,EAAE,SAAS,EAAoC,MAAM,iBAAiB,CAAA;AAC7E,OAAO,EACL,QAAQ,EACR,cAAc,EACd,cAAc,EAGd,aAAa,EACb,MAAM,EACP,MAAM,YAAY,CAAA;AAQnB;;;;;;;;;;GAUG;AACH,qBAAa,QAAQ,CACnB,KAAK,SAAS,aAAa,EAC3B,OAAO,GAAG,GAAG,CACb,SAAQ,YAAY,CAAC,cAAc,CAAC;;IAEpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IAexB;;;;;OAKG;gBACS,EACV,MAAM,EACN,QAAQ,EACR,MAAM,GACP,EAAE;QACD,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;QAC1B,+EAA+E;QAC/E,QAAQ,CAAC,EAAE,QAAQ,CAAA;QACnB,gEAAgE;QAChE,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB;IASD;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC;IA8ErE;;OAEG;IACH,aAAa;IAIb;;OAEG;IACH,aAAa;IAIb;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,SAAS,MAAM,KAAK,EACnC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;IAQvB;;;OAGG;IACH,IAAI,OAAO,YAEV;IAED;;;;;;;;;;OAUG;IACH,IAAI;IAeJ,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,gBAAgB;CAOzB"}