@fluidframework/presence 2.33.0-333010 → 2.33.0
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/README.md +24 -24
- package/dist/alpha.d.ts +29 -25
- package/dist/baseTypes.d.ts +3 -3
- package/dist/baseTypes.js.map +1 -1
- package/dist/broadcastControls.d.ts +1 -1
- package/dist/broadcastControls.js.map +1 -1
- package/dist/datastorePresenceManagerFactory.d.ts +5 -5
- package/dist/datastorePresenceManagerFactory.d.ts.map +1 -1
- package/dist/datastorePresenceManagerFactory.js +6 -6
- package/dist/datastorePresenceManagerFactory.js.map +1 -1
- package/dist/experimentalAccess.d.ts +4 -4
- package/dist/experimentalAccess.d.ts.map +1 -1
- package/dist/experimentalAccess.js +6 -6
- package/dist/experimentalAccess.js.map +1 -1
- package/dist/exposedInternalTypes.d.ts +1 -1
- package/dist/exposedInternalTypes.js.map +1 -1
- package/dist/exposedUtilityTypes.d.ts +0 -8
- package/dist/exposedUtilityTypes.d.ts.map +1 -1
- package/dist/exposedUtilityTypes.js.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/internalTypes.d.ts +3 -3
- package/dist/internalTypes.d.ts.map +1 -1
- package/dist/internalTypes.js.map +1 -1
- package/dist/internalUtils.d.ts +5 -0
- package/dist/internalUtils.d.ts.map +1 -1
- package/dist/internalUtils.js +8 -1
- package/dist/internalUtils.js.map +1 -1
- package/dist/latestMapValueManager.d.ts +57 -39
- package/dist/latestMapValueManager.d.ts.map +1 -1
- package/dist/latestMapValueManager.js +48 -39
- package/dist/latestMapValueManager.js.map +1 -1
- package/dist/latestValueManager.d.ts +38 -20
- package/dist/latestValueManager.d.ts.map +1 -1
- package/dist/latestValueManager.js +32 -28
- package/dist/latestValueManager.js.map +1 -1
- package/dist/latestValueTypes.d.ts +9 -10
- package/dist/latestValueTypes.d.ts.map +1 -1
- package/dist/latestValueTypes.js.map +1 -1
- package/dist/notificationsManager.d.ts +15 -10
- package/dist/notificationsManager.d.ts.map +1 -1
- package/dist/notificationsManager.js +8 -5
- package/dist/notificationsManager.js.map +1 -1
- package/dist/presence.d.ts +82 -66
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +5 -5
- package/dist/presence.js.map +1 -1
- package/dist/presenceDatastoreManager.d.ts +12 -10
- package/dist/presenceDatastoreManager.d.ts.map +1 -1
- package/dist/presenceDatastoreManager.js +10 -8
- package/dist/presenceDatastoreManager.js.map +1 -1
- package/dist/presenceManager.d.ts +2 -2
- package/dist/presenceManager.d.ts.map +1 -1
- package/dist/presenceManager.js +14 -22
- package/dist/presenceManager.js.map +1 -1
- package/dist/presenceStates.d.ts +14 -13
- package/dist/presenceStates.d.ts.map +1 -1
- package/dist/presenceStates.js +22 -15
- package/dist/presenceStates.js.map +1 -1
- package/dist/stateDatastore.d.ts +5 -4
- package/dist/stateDatastore.d.ts.map +1 -1
- package/dist/stateDatastore.js.map +1 -1
- package/dist/stateFactory.d.ts +22 -0
- package/dist/stateFactory.d.ts.map +1 -0
- package/dist/stateFactory.js +25 -0
- package/dist/stateFactory.js.map +1 -0
- package/dist/systemWorkspace.d.ts +7 -7
- package/dist/systemWorkspace.d.ts.map +1 -1
- package/dist/systemWorkspace.js +23 -23
- package/dist/systemWorkspace.js.map +1 -1
- package/dist/types.d.ts +50 -33
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/lib/alpha.d.ts +29 -25
- package/lib/baseTypes.d.ts +3 -3
- package/lib/baseTypes.js.map +1 -1
- package/lib/broadcastControls.d.ts +1 -1
- package/lib/broadcastControls.js.map +1 -1
- package/lib/datastorePresenceManagerFactory.d.ts +5 -5
- package/lib/datastorePresenceManagerFactory.d.ts.map +1 -1
- package/lib/datastorePresenceManagerFactory.js +4 -4
- package/lib/datastorePresenceManagerFactory.js.map +1 -1
- package/lib/experimentalAccess.d.ts +4 -4
- package/lib/experimentalAccess.d.ts.map +1 -1
- package/lib/experimentalAccess.js +4 -4
- package/lib/experimentalAccess.js.map +1 -1
- package/lib/exposedInternalTypes.d.ts +1 -1
- package/lib/exposedInternalTypes.js.map +1 -1
- package/lib/exposedUtilityTypes.d.ts +0 -8
- package/lib/exposedUtilityTypes.d.ts.map +1 -1
- package/lib/exposedUtilityTypes.js.map +1 -1
- package/lib/index.d.ts +8 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -5
- package/lib/index.js.map +1 -1
- package/lib/internalTypes.d.ts +3 -3
- package/lib/internalTypes.d.ts.map +1 -1
- package/lib/internalTypes.js.map +1 -1
- package/lib/internalUtils.d.ts +5 -0
- package/lib/internalUtils.d.ts.map +1 -1
- package/lib/internalUtils.js +6 -0
- package/lib/internalUtils.js.map +1 -1
- package/lib/latestMapValueManager.d.ts +57 -39
- package/lib/latestMapValueManager.d.ts.map +1 -1
- package/lib/latestMapValueManager.js +47 -38
- package/lib/latestMapValueManager.js.map +1 -1
- package/lib/latestValueManager.d.ts +38 -20
- package/lib/latestValueManager.d.ts.map +1 -1
- package/lib/latestValueManager.js +31 -27
- package/lib/latestValueManager.js.map +1 -1
- package/lib/latestValueTypes.d.ts +9 -10
- package/lib/latestValueTypes.d.ts.map +1 -1
- package/lib/latestValueTypes.js.map +1 -1
- package/lib/notificationsManager.d.ts +15 -10
- package/lib/notificationsManager.d.ts.map +1 -1
- package/lib/notificationsManager.js +8 -5
- package/lib/notificationsManager.js.map +1 -1
- package/lib/presence.d.ts +82 -66
- package/lib/presence.d.ts.map +1 -1
- package/lib/presence.js +4 -4
- package/lib/presence.js.map +1 -1
- package/lib/presenceDatastoreManager.d.ts +12 -10
- package/lib/presenceDatastoreManager.d.ts.map +1 -1
- package/lib/presenceDatastoreManager.js +10 -8
- package/lib/presenceDatastoreManager.js.map +1 -1
- package/lib/presenceManager.d.ts +2 -2
- package/lib/presenceManager.d.ts.map +1 -1
- package/lib/presenceManager.js +14 -22
- package/lib/presenceManager.js.map +1 -1
- package/lib/presenceStates.d.ts +14 -13
- package/lib/presenceStates.d.ts.map +1 -1
- package/lib/presenceStates.js +22 -15
- package/lib/presenceStates.js.map +1 -1
- package/lib/stateDatastore.d.ts +5 -4
- package/lib/stateDatastore.d.ts.map +1 -1
- package/lib/stateDatastore.js.map +1 -1
- package/lib/stateFactory.d.ts +22 -0
- package/lib/stateFactory.d.ts.map +1 -0
- package/lib/stateFactory.js +22 -0
- package/lib/stateFactory.js.map +1 -0
- package/lib/systemWorkspace.d.ts +7 -7
- package/lib/systemWorkspace.d.ts.map +1 -1
- package/lib/systemWorkspace.js +24 -24
- package/lib/systemWorkspace.js.map +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/lib/types.d.ts +50 -33
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +0 -1
- package/lib/types.js.map +1 -1
- package/package.json +19 -19
|
@@ -3,28 +3,27 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import type { Listenable } from "@fluidframework/core-interfaces";
|
|
6
|
-
import type { JsonDeserialized, JsonSerializable } from "@fluidframework/core-interfaces/internal/exposedUtilityTypes";
|
|
6
|
+
import type { DeepReadonly, JsonDeserialized, JsonSerializable } from "@fluidframework/core-interfaces/internal/exposedUtilityTypes";
|
|
7
7
|
import type { BroadcastControls, BroadcastControlSettings } from "./broadcastControls.js";
|
|
8
8
|
import type { InternalTypes } from "./exposedInternalTypes.js";
|
|
9
|
-
import type {
|
|
10
|
-
import type {
|
|
11
|
-
import type { ClientSessionId, ISessionClient } from "./presence.js";
|
|
9
|
+
import type { LatestClientData, LatestData, LatestMetadata } from "./latestValueTypes.js";
|
|
10
|
+
import type { AttendeeId, Attendee, Presence } from "./presence.js";
|
|
12
11
|
/**
|
|
13
12
|
* Collection of latest known values for a specific client.
|
|
14
13
|
*
|
|
15
14
|
* @sealed
|
|
16
15
|
* @alpha
|
|
17
16
|
*/
|
|
18
|
-
export interface
|
|
17
|
+
export interface LatestMapClientData<T, Keys extends string | number, SpecificAttendeeId extends AttendeeId = AttendeeId> {
|
|
19
18
|
/**
|
|
20
|
-
* Associated
|
|
19
|
+
* Associated attendee.
|
|
21
20
|
*/
|
|
22
|
-
|
|
21
|
+
attendee: Attendee<SpecificAttendeeId>;
|
|
23
22
|
/**
|
|
24
23
|
* @privateRemarks This could be regular map currently as no Map is
|
|
25
24
|
* stored internally and a new instance is created for every request.
|
|
26
25
|
*/
|
|
27
|
-
items: ReadonlyMap<Keys,
|
|
26
|
+
items: ReadonlyMap<Keys, LatestData<T>>;
|
|
28
27
|
}
|
|
29
28
|
/**
|
|
30
29
|
* State of a single item value, its key, and its metadata.
|
|
@@ -32,7 +31,7 @@ export interface LatestMapValueClientData<T, Keys extends string | number, Speci
|
|
|
32
31
|
* @sealed
|
|
33
32
|
* @alpha
|
|
34
33
|
*/
|
|
35
|
-
export interface
|
|
34
|
+
export interface LatestMapItemUpdatedClientData<T, K extends string | number> extends LatestClientData<T> {
|
|
36
35
|
key: K;
|
|
37
36
|
}
|
|
38
37
|
/**
|
|
@@ -42,15 +41,15 @@ export interface LatestMapItemValueClientData<T, K extends string | number> exte
|
|
|
42
41
|
* @alpha
|
|
43
42
|
*/
|
|
44
43
|
export interface LatestMapItemRemovedClientData<K extends string | number> {
|
|
45
|
-
|
|
44
|
+
attendee: Attendee;
|
|
46
45
|
key: K;
|
|
47
|
-
metadata:
|
|
46
|
+
metadata: LatestMetadata;
|
|
48
47
|
}
|
|
49
48
|
/**
|
|
50
49
|
* @sealed
|
|
51
50
|
* @alpha
|
|
52
51
|
*/
|
|
53
|
-
export interface
|
|
52
|
+
export interface LatestMapRawEvents<T, K extends string | number> {
|
|
54
53
|
/**
|
|
55
54
|
* Raised when any item's value for remote client is updated.
|
|
56
55
|
* @param updates - Map of one or more values updated.
|
|
@@ -59,21 +58,21 @@ export interface LatestMapValueManagerEvents<T, K extends string | number> {
|
|
|
59
58
|
*
|
|
60
59
|
* @eventProperty
|
|
61
60
|
*/
|
|
62
|
-
|
|
61
|
+
remoteUpdated: (updates: LatestMapClientData<T, K>) => void;
|
|
63
62
|
/**
|
|
64
63
|
* Raised when specific item's value of remote client is updated.
|
|
65
64
|
* @param updatedItem - Updated item value.
|
|
66
65
|
*
|
|
67
66
|
* @eventProperty
|
|
68
67
|
*/
|
|
69
|
-
|
|
68
|
+
remoteItemUpdated: (updatedItem: LatestMapItemUpdatedClientData<T, K>) => void;
|
|
70
69
|
/**
|
|
71
70
|
* Raised when specific item of remote client is removed.
|
|
72
71
|
* @param removedItem - Removed item.
|
|
73
72
|
*
|
|
74
73
|
* @eventProperty
|
|
75
74
|
*/
|
|
76
|
-
|
|
75
|
+
remoteItemRemoved: (removedItem: LatestMapItemRemovedClientData<K>) => void;
|
|
77
76
|
/**
|
|
78
77
|
* Raised when specific local item's value is updated.
|
|
79
78
|
* @param updatedItem - Updated item value.
|
|
@@ -81,7 +80,7 @@ export interface LatestMapValueManagerEvents<T, K extends string | number> {
|
|
|
81
80
|
* @eventProperty
|
|
82
81
|
*/
|
|
83
82
|
localItemUpdated: (updatedItem: {
|
|
84
|
-
value:
|
|
83
|
+
value: DeepReadonly<JsonSerializable<T> & JsonDeserialized<T>>;
|
|
85
84
|
key: K;
|
|
86
85
|
}) => void;
|
|
87
86
|
/**
|
|
@@ -100,14 +99,14 @@ export interface LatestMapValueManagerEvents<T, K extends string | number> {
|
|
|
100
99
|
* @sealed
|
|
101
100
|
* @alpha
|
|
102
101
|
*/
|
|
103
|
-
export interface
|
|
102
|
+
export interface StateMap<K extends string | number, V> {
|
|
104
103
|
/**
|
|
105
|
-
* ${@link
|
|
104
|
+
* ${@link StateMap.delete}s all elements in the StateMap.
|
|
106
105
|
* @remarks This is not yet implemented.
|
|
107
106
|
*/
|
|
108
107
|
clear(): void;
|
|
109
108
|
/**
|
|
110
|
-
* @returns true if an element in the
|
|
109
|
+
* @returns true if an element in the StateMap existed and has been removed, or false if
|
|
111
110
|
* the element does not exist.
|
|
112
111
|
* @remarks No entry is fully removed. Instead an undefined placeholder is locally and
|
|
113
112
|
* transmitted to all other clients. For better performance limit the number of deleted
|
|
@@ -117,20 +116,20 @@ export interface ValueMap<K extends string | number, V> {
|
|
|
117
116
|
*/
|
|
118
117
|
delete(key: K): boolean;
|
|
119
118
|
/**
|
|
120
|
-
* Executes a provided function once per each key/value pair in the
|
|
119
|
+
* Executes a provided function once per each key/value pair in the StateMap, in arbitrary order.
|
|
121
120
|
*/
|
|
122
|
-
forEach(callbackfn: (value:
|
|
121
|
+
forEach(callbackfn: (value: DeepReadonly<JsonDeserialized<V>>, key: K, map: StateMap<K, V>) => void, thisArg?: unknown): void;
|
|
123
122
|
/**
|
|
124
|
-
* Returns a specified element from the
|
|
123
|
+
* Returns a specified element from the StateMap object.
|
|
125
124
|
* @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
|
|
126
125
|
*/
|
|
127
|
-
get(key: K):
|
|
126
|
+
get(key: K): DeepReadonly<JsonDeserialized<V>> | undefined;
|
|
128
127
|
/**
|
|
129
128
|
* @returns boolean indicating whether an element with the specified key exists or not.
|
|
130
129
|
*/
|
|
131
130
|
has(key: K): boolean;
|
|
132
131
|
/**
|
|
133
|
-
* Adds a new element with a specified key and value to the
|
|
132
|
+
* Adds a new element with a specified key and value to the StateMap. If an element with the same key already exists, the element will be updated.
|
|
134
133
|
* The value will be transmitted to all other connected clients.
|
|
135
134
|
*
|
|
136
135
|
* @remarks Manager assumes ownership of the value and its references.
|
|
@@ -139,7 +138,7 @@ export interface ValueMap<K extends string | number, V> {
|
|
|
139
138
|
*/
|
|
140
139
|
set(key: K, value: JsonSerializable<V> & JsonDeserialized<V>): this;
|
|
141
140
|
/**
|
|
142
|
-
* @returns the number of elements in the
|
|
141
|
+
* @returns the number of elements in the StateMap.
|
|
143
142
|
*/
|
|
144
143
|
readonly size: number;
|
|
145
144
|
/**
|
|
@@ -154,21 +153,25 @@ export interface ValueMap<K extends string | number, V> {
|
|
|
154
153
|
keys(): IterableIterator<K>;
|
|
155
154
|
}
|
|
156
155
|
/**
|
|
157
|
-
*
|
|
156
|
+
* State that provides a `Map` of latest known values from this client to
|
|
158
157
|
* others and read access to their values.
|
|
159
158
|
* Entries in the map may vary over time and by client, but all values are expected to
|
|
160
159
|
* be of the same type, which may be a union type.
|
|
161
160
|
*
|
|
162
|
-
* @remarks Create using {@link
|
|
161
|
+
* @remarks Create using {@link StateFactory.latestMap} registered to {@link StatesWorkspace}.
|
|
163
162
|
*
|
|
164
163
|
* @sealed
|
|
165
164
|
* @alpha
|
|
166
165
|
*/
|
|
167
|
-
export interface
|
|
166
|
+
export interface LatestMapRaw<T, Keys extends string | number = string | number> {
|
|
168
167
|
/**
|
|
169
|
-
*
|
|
168
|
+
* Containing {@link Presence}
|
|
170
169
|
*/
|
|
171
|
-
readonly
|
|
170
|
+
readonly presence: Presence;
|
|
171
|
+
/**
|
|
172
|
+
* Events for LatestMapRaw.
|
|
173
|
+
*/
|
|
174
|
+
readonly events: Listenable<LatestMapRawEvents<T, Keys>>;
|
|
172
175
|
/**
|
|
173
176
|
* Controls for management of sending updates.
|
|
174
177
|
*/
|
|
@@ -176,26 +179,41 @@ export interface LatestMapValueManager<T, Keys extends string | number = string
|
|
|
176
179
|
/**
|
|
177
180
|
* Current value map for this client.
|
|
178
181
|
*/
|
|
179
|
-
readonly local:
|
|
182
|
+
readonly local: StateMap<Keys, T>;
|
|
180
183
|
/**
|
|
181
184
|
* Iterable access to remote clients' map of values.
|
|
182
185
|
*/
|
|
183
|
-
|
|
186
|
+
getRemotes(): IterableIterator<LatestMapClientData<T, Keys>>;
|
|
184
187
|
/**
|
|
185
|
-
* Array of
|
|
188
|
+
* Array of {@link Attendee}s that have provided states.
|
|
186
189
|
*/
|
|
187
|
-
|
|
190
|
+
getStateAttendees(): Attendee[];
|
|
188
191
|
/**
|
|
189
192
|
* Access to a specific client's map of values.
|
|
190
193
|
*/
|
|
191
|
-
|
|
194
|
+
getRemote(attendee: Attendee): ReadonlyMap<Keys, LatestData<T>>;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Arguments that are passed to the {@link StateFactory.latestMap} function.
|
|
198
|
+
*
|
|
199
|
+
* @alpha
|
|
200
|
+
*/
|
|
201
|
+
export interface LatestMapArguments<T, Keys extends string | number = string | number> {
|
|
202
|
+
/**
|
|
203
|
+
* The initial value of the local state.
|
|
204
|
+
*/
|
|
205
|
+
local?: {
|
|
206
|
+
[K in Keys]: JsonSerializable<T> & JsonDeserialized<T>;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* See {@link BroadcastControlSettings}.
|
|
210
|
+
*/
|
|
211
|
+
settings?: BroadcastControlSettings | undefined;
|
|
192
212
|
}
|
|
193
213
|
/**
|
|
194
|
-
* Factory for creating a {@link
|
|
214
|
+
* Factory for creating a {@link LatestMapRaw} State object.
|
|
195
215
|
*
|
|
196
216
|
* @alpha
|
|
197
217
|
*/
|
|
198
|
-
export declare function
|
|
199
|
-
[K in Keys]: JsonSerializable<T> & JsonDeserialized<T>;
|
|
200
|
-
}, controls?: BroadcastControlSettings): InternalTypes.ManagerFactory<RegistrationKey, InternalTypes.MapValueState<T, Keys>, LatestMapValueManager<T, Keys>>;
|
|
218
|
+
export declare function latestMap<T, Keys extends string | number = string | number, RegistrationKey extends string = string>(args?: LatestMapArguments<T, Keys>): InternalTypes.ManagerFactory<RegistrationKey, InternalTypes.MapValueState<T, Keys>, LatestMapRaw<T, Keys>>;
|
|
201
219
|
//# sourceMappingURL=latestMapValueManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"latestMapValueManager.d.ts","sourceRoot":"","sources":["../src/latestMapValueManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,8DAA8D,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAE1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"latestMapValueManager.d.ts","sourceRoot":"","sources":["../src/latestMapValueManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createEmitter } from "@fluid-internal/client-utils";
|
|
6
6
|
import { OptionalBroadcastControl } from "./broadcastControls.js";
|
|
7
|
-
import { objectEntries, objectKeys } from "./internalUtils.js";
|
|
7
|
+
import { asDeeplyReadonly, objectEntries, objectKeys } from "./internalUtils.js";
|
|
8
8
|
import { datastoreFromHandle } from "./stateDatastore.js";
|
|
9
9
|
import { brandIVM } from "./valueManager.js";
|
|
10
10
|
class ValueMapImpl {
|
|
@@ -51,12 +51,12 @@ class ValueMapImpl {
|
|
|
51
51
|
forEach(callbackfn, thisArg) {
|
|
52
52
|
for (const [key, item] of objectEntries(this.value.items)) {
|
|
53
53
|
if (item.value !== undefined) {
|
|
54
|
-
callbackfn(item.value, key, this);
|
|
54
|
+
callbackfn(asDeeplyReadonly(item.value), key, this);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
get(key) {
|
|
59
|
-
return this.value.items[key]?.value;
|
|
59
|
+
return asDeeplyReadonly(this.value.items[key]?.value);
|
|
60
60
|
}
|
|
61
61
|
has(key) {
|
|
62
62
|
return this.value.items[key]?.value !== undefined;
|
|
@@ -67,7 +67,7 @@ class ValueMapImpl {
|
|
|
67
67
|
this.value.items[key] = { rev: 0, timestamp: 0, value };
|
|
68
68
|
}
|
|
69
69
|
this.updateItem(key, value);
|
|
70
|
-
this.emitter.emit("localItemUpdated", { key, value });
|
|
70
|
+
this.emitter.emit("localItemUpdated", { key, value: asDeeplyReadonly(value) });
|
|
71
71
|
return this;
|
|
72
72
|
}
|
|
73
73
|
get size() {
|
|
@@ -83,7 +83,7 @@ class ValueMapImpl {
|
|
|
83
83
|
return keys[Symbol.iterator]();
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
class
|
|
86
|
+
class LatestMapRawValueManagerImpl {
|
|
87
87
|
constructor(key, datastore, value, controlSettings) {
|
|
88
88
|
this.key = key;
|
|
89
89
|
this.datastore = datastore;
|
|
@@ -96,46 +96,49 @@ class LatestMapValueManagerImpl {
|
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
get presence() {
|
|
100
|
+
return this.datastore.presence;
|
|
101
|
+
}
|
|
102
|
+
*getRemotes() {
|
|
100
103
|
const allKnownStates = this.datastore.knownValues(this.key);
|
|
101
|
-
for (const
|
|
102
|
-
if (
|
|
103
|
-
const
|
|
104
|
-
const items = this.
|
|
105
|
-
yield {
|
|
104
|
+
for (const attendeeId of objectKeys(allKnownStates.states)) {
|
|
105
|
+
if (attendeeId !== allKnownStates.self) {
|
|
106
|
+
const attendee = this.datastore.lookupClient(attendeeId);
|
|
107
|
+
const items = this.getRemote(attendee);
|
|
108
|
+
yield { attendee, items };
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
|
-
|
|
112
|
+
getStateAttendees() {
|
|
110
113
|
const allKnownStates = this.datastore.knownValues(this.key);
|
|
111
114
|
return objectKeys(allKnownStates.states)
|
|
112
|
-
.filter((
|
|
113
|
-
.map((
|
|
115
|
+
.filter((attendeeId) => attendeeId !== allKnownStates.self)
|
|
116
|
+
.map((attendeeId) => this.datastore.lookupClient(attendeeId));
|
|
114
117
|
}
|
|
115
|
-
|
|
118
|
+
getRemote(attendee) {
|
|
116
119
|
const allKnownStates = this.datastore.knownValues(this.key);
|
|
117
|
-
const
|
|
118
|
-
const clientStateMap = allKnownStates.states[
|
|
120
|
+
const attendeeId = attendee.attendeeId;
|
|
121
|
+
const clientStateMap = allKnownStates.states[attendeeId];
|
|
119
122
|
if (clientStateMap === undefined) {
|
|
120
|
-
throw new Error("No entry for
|
|
123
|
+
throw new Error("No entry for attendee");
|
|
121
124
|
}
|
|
122
125
|
const items = new Map();
|
|
123
126
|
for (const [key, item] of objectEntries(clientStateMap.items)) {
|
|
124
127
|
const value = item.value;
|
|
125
128
|
if (value !== undefined) {
|
|
126
129
|
items.set(key, {
|
|
127
|
-
value,
|
|
130
|
+
value: asDeeplyReadonly(value),
|
|
128
131
|
metadata: { revision: item.rev, timestamp: item.timestamp },
|
|
129
132
|
});
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
return items;
|
|
133
136
|
}
|
|
134
|
-
update(
|
|
137
|
+
update(attendee, _received, value) {
|
|
135
138
|
const allKnownStates = this.datastore.knownValues(this.key);
|
|
136
|
-
const
|
|
137
|
-
const currentState = (allKnownStates.states[
|
|
138
|
-
// New
|
|
139
|
+
const attendeeId = attendee.attendeeId;
|
|
140
|
+
const currentState = (allKnownStates.states[attendeeId] ??=
|
|
141
|
+
// New attendee - prepare new attendee state directory
|
|
139
142
|
{
|
|
140
143
|
rev: value.rev,
|
|
141
144
|
items: {},
|
|
@@ -157,7 +160,7 @@ class LatestMapValueManagerImpl {
|
|
|
157
160
|
currentState.rev = value.rev;
|
|
158
161
|
}
|
|
159
162
|
const allUpdates = {
|
|
160
|
-
|
|
163
|
+
attendee,
|
|
161
164
|
items: new Map(),
|
|
162
165
|
};
|
|
163
166
|
const postUpdateActions = [];
|
|
@@ -168,47 +171,53 @@ class LatestMapValueManagerImpl {
|
|
|
168
171
|
currentState.items[key] = item;
|
|
169
172
|
const metadata = { revision: item.rev, timestamp: item.timestamp };
|
|
170
173
|
if (item.value !== undefined) {
|
|
171
|
-
const itemValue = item.value;
|
|
174
|
+
const itemValue = asDeeplyReadonly(item.value);
|
|
172
175
|
const updatedItem = {
|
|
173
|
-
|
|
176
|
+
attendee,
|
|
174
177
|
key,
|
|
175
178
|
value: itemValue,
|
|
176
179
|
metadata,
|
|
177
180
|
};
|
|
178
|
-
postUpdateActions.push(() => this.events.emit("
|
|
181
|
+
postUpdateActions.push(() => this.events.emit("remoteItemUpdated", updatedItem));
|
|
179
182
|
allUpdates.items.set(key, { value: itemValue, metadata });
|
|
180
183
|
}
|
|
181
184
|
else if (hadPriorValue !== undefined) {
|
|
182
|
-
postUpdateActions.push(() => this.events.emit("
|
|
183
|
-
|
|
185
|
+
postUpdateActions.push(() => this.events.emit("remoteItemRemoved", {
|
|
186
|
+
attendee,
|
|
184
187
|
key,
|
|
185
188
|
metadata,
|
|
186
189
|
}));
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
|
-
this.datastore.update(this.key,
|
|
190
|
-
postUpdateActions.push(() => this.events.emit("
|
|
192
|
+
this.datastore.update(this.key, attendeeId, currentState);
|
|
193
|
+
postUpdateActions.push(() => this.events.emit("remoteUpdated", allUpdates));
|
|
191
194
|
return postUpdateActions;
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
197
|
/**
|
|
195
|
-
* Factory for creating a {@link
|
|
198
|
+
* Factory for creating a {@link LatestMapRaw} State object.
|
|
196
199
|
*
|
|
197
200
|
* @alpha
|
|
198
201
|
*/
|
|
199
|
-
export function
|
|
202
|
+
export function latestMap(args) {
|
|
203
|
+
const settings = args?.settings;
|
|
204
|
+
const initialValues = args?.local;
|
|
200
205
|
const timestamp = Date.now();
|
|
201
206
|
const value = { rev: 0, items: {} };
|
|
202
|
-
//
|
|
207
|
+
// LatestMapRaw takes ownership of values within initialValues.
|
|
203
208
|
if (initialValues !== undefined) {
|
|
204
209
|
for (const key of objectKeys(initialValues)) {
|
|
205
|
-
value.items[key] = {
|
|
210
|
+
value.items[key] = {
|
|
211
|
+
rev: 0,
|
|
212
|
+
timestamp,
|
|
213
|
+
value: initialValues[key],
|
|
214
|
+
};
|
|
206
215
|
}
|
|
207
216
|
}
|
|
208
217
|
const factory = (key, datastoreHandle) => ({
|
|
209
|
-
initialData: { value, allowableUpdateLatencyMs:
|
|
210
|
-
manager: brandIVM(new
|
|
218
|
+
initialData: { value, allowableUpdateLatencyMs: settings?.allowableUpdateLatencyMs },
|
|
219
|
+
manager: brandIVM(new LatestMapRawValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, settings)),
|
|
211
220
|
});
|
|
212
|
-
return Object.assign(factory, { instanceBase:
|
|
221
|
+
return Object.assign(factory, { instanceBase: LatestMapRawValueManagerImpl });
|
|
213
222
|
}
|
|
214
223
|
//# sourceMappingURL=latestMapValueManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"latestMapValueManager.js","sourceRoot":"","sources":["../src/latestMapValueManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\nimport type { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/core-interfaces/internal/exposedUtilityTypes\";\n\nimport type { BroadcastControls, BroadcastControlSettings } from \"./broadcastControls.js\";\nimport { OptionalBroadcastControl } from \"./broadcastControls.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type { InternalUtilityTypes } from \"./exposedUtilityTypes.js\";\nimport type { PostUpdateAction, ValueManager } from \"./internalTypes.js\";\nimport { objectEntries, objectKeys } from \"./internalUtils.js\";\nimport type {\n\tLatestValueClientData,\n\tLatestValueData,\n\tLatestValueMetadata,\n} from \"./latestValueTypes.js\";\nimport type { ClientSessionId, ISessionClient, SpecificSessionClient } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\n/**\n * Collection of latest known values for a specific client.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapValueClientData<\n\tT,\n\tKeys extends string | number,\n\tSpecificSessionClientId extends ClientSessionId = ClientSessionId,\n> {\n\t/**\n\t * Associated client.\n\t */\n\tclient: ISessionClient<SpecificSessionClientId>;\n\n\t/**\n\t * @privateRemarks This could be regular map currently as no Map is\n\t * stored internally and a new instance is created for every request.\n\t */\n\titems: ReadonlyMap<Keys, LatestValueData<T>>;\n}\n\n/**\n * State of a single item value, its key, and its metadata.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapItemValueClientData<T, K extends string | number>\n\textends LatestValueClientData<T> {\n\tkey: K;\n}\n\n/**\n * Identifier and metadata for a removed item.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapItemRemovedClientData<K extends string | number> {\n\tclient: ISessionClient;\n\tkey: K;\n\tmetadata: LatestValueMetadata;\n}\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestMapValueManagerEvents<T, K extends string | number> {\n\t/**\n\t * Raised when any item's value for remote client is updated.\n\t * @param updates - Map of one or more values updated.\n\t *\n\t * @remarks The event does not include item removals.\n\t *\n\t * @eventProperty\n\t */\n\tupdated: (updates: LatestMapValueClientData<T, K>) => void;\n\n\t/**\n\t * Raised when specific item's value of remote client is updated.\n\t * @param updatedItem - Updated item value.\n\t *\n\t * @eventProperty\n\t */\n\titemUpdated: (updatedItem: LatestMapItemValueClientData<T, K>) => void;\n\n\t/**\n\t * Raised when specific item of remote client is removed.\n\t * @param removedItem - Removed item.\n\t *\n\t * @eventProperty\n\t */\n\titemRemoved: (removedItem: LatestMapItemRemovedClientData<K>) => void;\n\n\t/**\n\t * Raised when specific local item's value is updated.\n\t * @param updatedItem - Updated item value.\n\t *\n\t * @eventProperty\n\t */\n\tlocalItemUpdated: (updatedItem: {\n\t\tvalue: InternalUtilityTypes.FullyReadonly<JsonSerializable<T> & JsonDeserialized<T>>;\n\t\tkey: K;\n\t}) => void;\n\n\t/**\n\t * Raised when specific local item is removed.\n\t * @param removedItem - Removed item.\n\t *\n\t * @eventProperty\n\t */\n\tlocalItemRemoved: (removedItem: {\n\t\tkey: K;\n\t}) => void;\n}\n\n/**\n * Map of local client's values. Modifications are transmitted to all other connected clients.\n *\n * @sealed\n * @alpha\n */\nexport interface ValueMap<K extends string | number, V> {\n\t/**\n\t * ${@link ValueMap.delete}s all elements in the ValueMap.\n\t * @remarks This is not yet implemented.\n\t */\n\tclear(): void;\n\n\t/**\n\t * @returns true if an element in the ValueMap existed and has been removed, or false if\n\t * the element does not exist.\n\t * @remarks No entry is fully removed. Instead an undefined placeholder is locally and\n\t * transmitted to all other clients. For better performance limit the number of deleted\n\t * entries and reuse keys when possible.\n\t * @privateRemarks In the future we may add a mechanism to remove the placeholder, at least\n\t * from transmissions after sufficient time has passed.\n\t */\n\tdelete(key: K): boolean;\n\n\t/**\n\t * Executes a provided function once per each key/value pair in the ValueMap, in arbitrary order.\n\t */\n\tforEach(\n\t\tcallbackfn: (\n\t\t\tvalue: InternalUtilityTypes.FullyReadonly<JsonDeserialized<V>>,\n\t\t\tkey: K,\n\t\t\tmap: ValueMap<K, V>,\n\t\t) => void,\n\t\tthisArg?: unknown,\n\t): void;\n\n\t/**\n\t * Returns a specified element from the ValueMap object.\n\t * @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.\n\t */\n\tget(key: K): InternalUtilityTypes.FullyReadonly<JsonDeserialized<V>> | undefined;\n\n\t/**\n\t * @returns boolean indicating whether an element with the specified key exists or not.\n\t */\n\thas(key: K): boolean;\n\n\t/**\n\t * Adds a new element with a specified key and value to the ValueMap. If an element with the same key already exists, the element will be updated.\n\t * The value will be transmitted to all other connected clients.\n\t *\n\t * @remarks Manager assumes ownership of the value and its references.\n\t * Make a deep clone before setting, if needed. No comparison is done to detect changes; all\n\t * sets are transmitted.\n\t */\n\tset(key: K, value: JsonSerializable<V> & JsonDeserialized<V>): this;\n\n\t/**\n\t * @returns the number of elements in the ValueMap.\n\t */\n\treadonly size: number;\n\n\t/**\n\t * Returns an iterable of entries in the map.\n\t */\n\t// [Symbol.iterator](): IterableIterator<[K, InternalUtilityTypes.FullyReadonly<JsonDeserialized<V>>]>;\n\n\t/**\n\t * Returns an iterable of key, value pairs for every entry in the map.\n\t */\n\t// entries(): IterableIterator<[K, InternalUtilityTypes.FullyReadonly<JsonDeserialized<V>>]>;\n\n\t/**\n\t * Returns an iterable of keys in the map.\n\t */\n\tkeys(): IterableIterator<K>;\n\n\t/**\n\t * Returns an iterable of values in the map.\n\t */\n\t// values(): IterableIterator<InternalUtilityTypes.FullyReadonly<JsonDeserialized<V>>>;\n}\n\nclass ValueMapImpl<T, K extends string | number> implements ValueMap<K, T> {\n\tprivate countDefined: number;\n\tpublic constructor(\n\t\tprivate readonly value: InternalTypes.MapValueState<T, K>,\n\t\tprivate readonly emitter: IEmitter<\n\t\t\tPick<LatestMapValueManagerEvents<T, K>, \"localItemUpdated\" | \"localItemRemoved\">\n\t\t>,\n\t\tprivate readonly localUpdate: (\n\t\t\tupdates: InternalTypes.MapValueState<\n\t\t\t\tT,\n\t\t\t\t// This should be `K`, but will only work if properties are optional.\n\t\t\t\tstring | number\n\t\t\t>,\n\t\t) => void,\n\t) {\n\t\t// All initial items are expected to be defined.\n\t\t// TODO assert all defined and/or update type.\n\t\tthis.countDefined = Object.keys(value.items).length;\n\t}\n\n\t/**\n\t * Note: caller must ensure key exists in this.value.items.\n\t */\n\tprivate updateItem(key: K, value: InternalTypes.ValueOptionalState<T>[\"value\"]): void {\n\t\tthis.value.rev += 1;\n\t\t// Caller is required to ensure key exists.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst item = this.value.items[key]!;\n\t\titem.rev += 1;\n\t\titem.timestamp = Date.now();\n\t\tif (value === undefined) {\n\t\t\tdelete item.value;\n\t\t} else {\n\t\t\titem.value = value;\n\t\t}\n\t\tconst update = { rev: this.value.rev, items: { [key]: item } };\n\t\tthis.localUpdate(update);\n\t}\n\n\tpublic clear(): void {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\tpublic delete(key: K): boolean {\n\t\tconst { items } = this.value;\n\t\tconst hasKey = items[key]?.value !== undefined;\n\t\tif (hasKey) {\n\t\t\tthis.countDefined -= 1;\n\t\t\tthis.updateItem(key, undefined);\n\t\t\tthis.emitter.emit(\"localItemRemoved\", { key });\n\t\t}\n\t\treturn hasKey;\n\t}\n\tpublic forEach(\n\t\tcallbackfn: (\n\t\t\tvalue: InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>,\n\t\t\tkey: K,\n\t\t\tmap: ValueMap<K, T>,\n\t\t) => void,\n\t\tthisArg?: unknown,\n\t): void {\n\t\tfor (const [key, item] of objectEntries(this.value.items)) {\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tcallbackfn(item.value, key, this);\n\t\t\t}\n\t\t}\n\t}\n\tpublic get(key: K): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>> | undefined {\n\t\treturn this.value.items[key]?.value;\n\t}\n\tpublic has(key: K): boolean {\n\t\treturn this.value.items[key]?.value !== undefined;\n\t}\n\tpublic set(key: K, value: JsonSerializable<T> & JsonDeserialized<T>): this {\n\t\tif (!(key in this.value.items)) {\n\t\t\tthis.countDefined += 1;\n\t\t\tthis.value.items[key] = { rev: 0, timestamp: 0, value };\n\t\t}\n\t\tthis.updateItem(key, value);\n\t\tthis.emitter.emit(\"localItemUpdated\", { key, value });\n\t\treturn this;\n\t}\n\tpublic get size(): number {\n\t\treturn this.countDefined;\n\t}\n\tpublic keys(): IterableIterator<K> {\n\t\tconst keys: K[] = [];\n\t\tfor (const [key, item] of objectEntries(this.value.items)) {\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tkeys.push(key);\n\t\t\t}\n\t\t}\n\t\treturn keys[Symbol.iterator]();\n\t}\n}\n\n/**\n * Value manager that provides a `Map` of latest known values from this client to\n * others and read access to their values.\n * Entries in the map may vary over time and by client, but all values are expected to\n * be of the same type, which may be a union type.\n *\n * @remarks Create using {@link LatestMap} registered to {@link PresenceStates}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapValueManager<T, Keys extends string | number = string | number> {\n\t/**\n\t * Events for LatestMap value manager.\n\t */\n\treadonly events: Listenable<LatestMapValueManagerEvents<T, Keys>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: BroadcastControls;\n\n\t/**\n\t * Current value map for this client.\n\t */\n\treadonly local: ValueMap<Keys, T>;\n\t/**\n\t * Iterable access to remote clients' map of values.\n\t */\n\tclientValues(): IterableIterator<LatestMapValueClientData<T, Keys>>;\n\t/**\n\t * Array of known remote clients.\n\t */\n\tclients(): ISessionClient[];\n\t/**\n\t * Access to a specific client's map of values.\n\t */\n\tclientValue(client: ISessionClient): ReadonlyMap<Keys, LatestValueData<T>>;\n}\n\nclass LatestMapValueManagerImpl<\n\tT,\n\tRegistrationKey extends string,\n\tKeys extends string | number = string | number,\n> implements\n\t\tLatestMapValueManager<T, Keys>,\n\t\tRequired<ValueManager<T, InternalTypes.MapValueState<T, Keys>>>\n{\n\tpublic readonly events = createEmitter<LatestMapValueManagerEvents<T, Keys>>();\n\tpublic readonly controls: OptionalBroadcastControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: RegistrationKey,\n\t\tprivate readonly datastore: StateDatastore<\n\t\t\tRegistrationKey,\n\t\t\tInternalTypes.MapValueState<T, Keys>\n\t\t>,\n\t\tpublic readonly value: InternalTypes.MapValueState<T, Keys>,\n\t\tcontrolSettings: BroadcastControlSettings | undefined,\n\t) {\n\t\tthis.controls = new OptionalBroadcastControl(controlSettings);\n\n\t\tthis.local = new ValueMapImpl<T, Keys>(\n\t\t\tvalue,\n\t\t\tthis.events,\n\t\t\t(updates: InternalTypes.MapValueState<T, Keys>) => {\n\t\t\t\tdatastore.localUpdate(key, updates, {\n\t\t\t\t\tallowableUpdateLatencyMs: this.controls.allowableUpdateLatencyMs,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic readonly local: ValueMap<Keys, T>;\n\n\tpublic *clientValues(): IterableIterator<LatestMapValueClientData<T, Keys>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const clientSessionId of objectKeys(allKnownStates.states)) {\n\t\t\tif (clientSessionId !== allKnownStates.self) {\n\t\t\t\tconst client = this.datastore.lookupClient(clientSessionId);\n\t\t\t\tconst items = this.clientValue(client);\n\t\t\t\tyield { client, items };\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic clients(): ISessionClient[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\treturn objectKeys(allKnownStates.states)\n\t\t\t.filter((clientSessionId) => clientSessionId !== allKnownStates.self)\n\t\t\t.map((clientSessionId) => this.datastore.lookupClient(clientSessionId));\n\t}\n\n\tpublic clientValue(client: ISessionClient): ReadonlyMap<Keys, LatestValueData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tconst clientStateMap = allKnownStates.states[clientSessionId];\n\t\tif (clientStateMap === undefined) {\n\t\t\tthrow new Error(\"No entry for client\");\n\t\t}\n\t\tconst items = new Map<Keys, LatestValueData<T>>();\n\t\tfor (const [key, item] of objectEntries(clientStateMap.items)) {\n\t\t\tconst value = item.value;\n\t\t\tif (value !== undefined) {\n\t\t\t\titems.set(key, {\n\t\t\t\t\tvalue,\n\t\t\t\t\tmetadata: { revision: item.rev, timestamp: item.timestamp },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn items;\n\t}\n\n\tpublic update<SpecificSessionClientId extends ClientSessionId>(\n\t\tclient: SpecificSessionClient<SpecificSessionClientId>,\n\t\t_received: number,\n\t\tvalue: InternalTypes.MapValueState<T, string | number>,\n\t): PostUpdateAction[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId: SpecificSessionClientId = client.sessionId;\n\t\tconst currentState = (allKnownStates.states[clientSessionId] ??=\n\t\t\t// New client - prepare new client state directory\n\t\t\t{\n\t\t\t\trev: value.rev,\n\t\t\t\titems: {} as unknown as InternalTypes.MapValueState<T, Keys>[\"items\"],\n\t\t\t});\n\t\t// Accumulate individual update keys\n\t\tconst updatedItemKeys: Keys[] = [];\n\t\tfor (const [key, item] of objectEntries(value.items)) {\n\t\t\t// TODO: Key validation needs to be added here.\n\t\t\tconst validKey = key as Keys;\n\t\t\tif (!(key in currentState.items) || currentState.items[validKey].rev < item.rev) {\n\t\t\t\tupdatedItemKeys.push(validKey);\n\t\t\t}\n\t\t}\n\n\t\tif (updatedItemKeys.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Store updates\n\t\tif (value.rev > currentState.rev) {\n\t\t\tcurrentState.rev = value.rev;\n\t\t}\n\t\tconst allUpdates = {\n\t\t\tclient,\n\t\t\titems: new Map<Keys, LatestValueData<T>>(),\n\t\t};\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\t\tfor (const key of updatedItemKeys) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst item = value.items[key]!;\n\t\t\tconst hadPriorValue = currentState.items[key]?.value;\n\t\t\tcurrentState.items[key] = item;\n\t\t\tconst metadata = { revision: item.rev, timestamp: item.timestamp };\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tconst itemValue = item.value;\n\t\t\t\tconst updatedItem = {\n\t\t\t\t\tclient,\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue: itemValue,\n\t\t\t\t\tmetadata,\n\t\t\t\t};\n\t\t\t\tpostUpdateActions.push(() => this.events.emit(\"itemUpdated\", updatedItem));\n\t\t\t\tallUpdates.items.set(key, { value: itemValue, metadata });\n\t\t\t} else if (hadPriorValue !== undefined) {\n\t\t\t\tpostUpdateActions.push(() =>\n\t\t\t\t\tthis.events.emit(\"itemRemoved\", {\n\t\t\t\t\t\tclient,\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmetadata,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, currentState);\n\t\tpostUpdateActions.push(() => this.events.emit(\"updated\", allUpdates));\n\t\treturn postUpdateActions;\n\t}\n}\n\n/**\n * Factory for creating a {@link LatestMapValueManager}.\n *\n * @alpha\n */\nexport function LatestMap<\n\tT extends object,\n\tKeys extends string | number = string | number,\n\tRegistrationKey extends string = string,\n>(\n\tinitialValues?: {\n\t\t[K in Keys]: JsonSerializable<T> & JsonDeserialized<T>;\n\t},\n\tcontrols?: BroadcastControlSettings,\n): InternalTypes.ManagerFactory<\n\tRegistrationKey,\n\tInternalTypes.MapValueState<T, Keys>,\n\tLatestMapValueManager<T, Keys>\n> {\n\tconst timestamp = Date.now();\n\tconst value: InternalTypes.MapValueState<\n\t\tT,\n\t\t// This should be `Keys`, but will only work if properties are optional.\n\t\tstring | number\n\t> = { rev: 0, items: {} };\n\t// LatestMapValueManager takes ownership of values within initialValues.\n\tif (initialValues !== undefined) {\n\t\tfor (const key of objectKeys(initialValues)) {\n\t\t\tvalue.items[key] = { rev: 0, timestamp, value: initialValues[key] };\n\t\t}\n\t}\n\tconst factory = (\n\t\tkey: RegistrationKey,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tRegistrationKey,\n\t\t\tInternalTypes.MapValueState<T, Keys>\n\t\t>,\n\t): {\n\t\tinitialData: { value: typeof value; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: InternalTypes.StateValue<LatestMapValueManager<T, Keys>>;\n\t} => ({\n\t\tinitialData: { value, allowableUpdateLatencyMs: controls?.allowableUpdateLatencyMs },\n\t\tmanager: brandIVM<\n\t\t\tLatestMapValueManagerImpl<T, RegistrationKey, Keys>,\n\t\t\tT,\n\t\t\tInternalTypes.MapValueState<T, Keys>\n\t\t>(\n\t\t\tnew LatestMapValueManagerImpl(\n\t\t\t\tkey,\n\t\t\t\tdatastoreFromHandle(datastoreHandle),\n\t\t\t\tvalue,\n\t\t\t\tcontrols,\n\t\t\t),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestMapValueManagerImpl });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"latestMapValueManager.js","sourceRoot":"","sources":["../src/latestMapValueManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createEmitter } from \"@fluid-internal/client-utils\";\nimport type { Listenable } from \"@fluidframework/core-interfaces\";\nimport type { IEmitter } from \"@fluidframework/core-interfaces/internal\";\nimport type {\n\tDeepReadonly,\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/core-interfaces/internal/exposedUtilityTypes\";\n\nimport type { BroadcastControls, BroadcastControlSettings } from \"./broadcastControls.js\";\nimport { OptionalBroadcastControl } from \"./broadcastControls.js\";\nimport type { InternalTypes } from \"./exposedInternalTypes.js\";\nimport type { PostUpdateAction, ValueManager } from \"./internalTypes.js\";\nimport { asDeeplyReadonly, objectEntries, objectKeys } from \"./internalUtils.js\";\nimport type { LatestClientData, LatestData, LatestMetadata } from \"./latestValueTypes.js\";\nimport type { AttendeeId, Attendee, Presence, SpecificAttendee } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\n/**\n * Collection of latest known values for a specific client.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapClientData<\n\tT,\n\tKeys extends string | number,\n\tSpecificAttendeeId extends AttendeeId = AttendeeId,\n> {\n\t/**\n\t * Associated attendee.\n\t */\n\tattendee: Attendee<SpecificAttendeeId>;\n\n\t/**\n\t * @privateRemarks This could be regular map currently as no Map is\n\t * stored internally and a new instance is created for every request.\n\t */\n\titems: ReadonlyMap<Keys, LatestData<T>>;\n}\n\n/**\n * State of a single item value, its key, and its metadata.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapItemUpdatedClientData<T, K extends string | number>\n\textends LatestClientData<T> {\n\tkey: K;\n}\n\n/**\n * Identifier and metadata for a removed item.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapItemRemovedClientData<K extends string | number> {\n\tattendee: Attendee;\n\tkey: K;\n\tmetadata: LatestMetadata;\n}\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestMapRawEvents<T, K extends string | number> {\n\t/**\n\t * Raised when any item's value for remote client is updated.\n\t * @param updates - Map of one or more values updated.\n\t *\n\t * @remarks The event does not include item removals.\n\t *\n\t * @eventProperty\n\t */\n\tremoteUpdated: (updates: LatestMapClientData<T, K>) => void;\n\n\t/**\n\t * Raised when specific item's value of remote client is updated.\n\t * @param updatedItem - Updated item value.\n\t *\n\t * @eventProperty\n\t */\n\tremoteItemUpdated: (updatedItem: LatestMapItemUpdatedClientData<T, K>) => void;\n\n\t/**\n\t * Raised when specific item of remote client is removed.\n\t * @param removedItem - Removed item.\n\t *\n\t * @eventProperty\n\t */\n\tremoteItemRemoved: (removedItem: LatestMapItemRemovedClientData<K>) => void;\n\n\t/**\n\t * Raised when specific local item's value is updated.\n\t * @param updatedItem - Updated item value.\n\t *\n\t * @eventProperty\n\t */\n\tlocalItemUpdated: (updatedItem: {\n\t\tvalue: DeepReadonly<JsonSerializable<T> & JsonDeserialized<T>>;\n\t\tkey: K;\n\t}) => void;\n\n\t/**\n\t * Raised when specific local item is removed.\n\t * @param removedItem - Removed item.\n\t *\n\t * @eventProperty\n\t */\n\tlocalItemRemoved: (removedItem: {\n\t\tkey: K;\n\t}) => void;\n}\n\n/**\n * Map of local client's values. Modifications are transmitted to all other connected clients.\n *\n * @sealed\n * @alpha\n */\nexport interface StateMap<K extends string | number, V> {\n\t/**\n\t * ${@link StateMap.delete}s all elements in the StateMap.\n\t * @remarks This is not yet implemented.\n\t */\n\tclear(): void;\n\n\t/**\n\t * @returns true if an element in the StateMap existed and has been removed, or false if\n\t * the element does not exist.\n\t * @remarks No entry is fully removed. Instead an undefined placeholder is locally and\n\t * transmitted to all other clients. For better performance limit the number of deleted\n\t * entries and reuse keys when possible.\n\t * @privateRemarks In the future we may add a mechanism to remove the placeholder, at least\n\t * from transmissions after sufficient time has passed.\n\t */\n\tdelete(key: K): boolean;\n\n\t/**\n\t * Executes a provided function once per each key/value pair in the StateMap, in arbitrary order.\n\t */\n\tforEach(\n\t\tcallbackfn: (\n\t\t\tvalue: DeepReadonly<JsonDeserialized<V>>,\n\t\t\tkey: K,\n\t\t\tmap: StateMap<K, V>,\n\t\t) => void,\n\t\tthisArg?: unknown,\n\t): void;\n\n\t/**\n\t * Returns a specified element from the StateMap object.\n\t * @returns Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.\n\t */\n\tget(key: K): DeepReadonly<JsonDeserialized<V>> | undefined;\n\n\t/**\n\t * @returns boolean indicating whether an element with the specified key exists or not.\n\t */\n\thas(key: K): boolean;\n\n\t/**\n\t * Adds a new element with a specified key and value to the StateMap. If an element with the same key already exists, the element will be updated.\n\t * The value will be transmitted to all other connected clients.\n\t *\n\t * @remarks Manager assumes ownership of the value and its references.\n\t * Make a deep clone before setting, if needed. No comparison is done to detect changes; all\n\t * sets are transmitted.\n\t */\n\tset(key: K, value: JsonSerializable<V> & JsonDeserialized<V>): this;\n\n\t/**\n\t * @returns the number of elements in the StateMap.\n\t */\n\treadonly size: number;\n\n\t/**\n\t * Returns an iterable of entries in the map.\n\t */\n\t// [Symbol.iterator](): IterableIterator<[K, DeepReadonly<JsonDeserialized<V>>]>;\n\n\t/**\n\t * Returns an iterable of key, value pairs for every entry in the map.\n\t */\n\t// entries(): IterableIterator<[K, DeepReadonly<JsonDeserialized<V>>]>;\n\n\t/**\n\t * Returns an iterable of keys in the map.\n\t */\n\tkeys(): IterableIterator<K>;\n\n\t/**\n\t * Returns an iterable of values in the map.\n\t */\n\t// values(): IterableIterator<DeepReadonly<JsonDeserialized<V>>>;\n}\n\nclass ValueMapImpl<T, K extends string | number> implements StateMap<K, T> {\n\tprivate countDefined: number;\n\tpublic constructor(\n\t\tprivate readonly value: InternalTypes.MapValueState<T, K>,\n\t\tprivate readonly emitter: IEmitter<\n\t\t\tPick<LatestMapRawEvents<T, K>, \"localItemUpdated\" | \"localItemRemoved\">\n\t\t>,\n\t\tprivate readonly localUpdate: (\n\t\t\tupdates: InternalTypes.MapValueState<\n\t\t\t\tT,\n\t\t\t\t// This should be `K`, but will only work if properties are optional.\n\t\t\t\tstring | number\n\t\t\t>,\n\t\t) => void,\n\t) {\n\t\t// All initial items are expected to be defined.\n\t\t// TODO assert all defined and/or update type.\n\t\tthis.countDefined = Object.keys(value.items).length;\n\t}\n\n\t/**\n\t * Note: caller must ensure key exists in this.value.items.\n\t */\n\tprivate updateItem(key: K, value: InternalTypes.ValueOptionalState<T>[\"value\"]): void {\n\t\tthis.value.rev += 1;\n\t\t// Caller is required to ensure key exists.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst item = this.value.items[key]!;\n\t\titem.rev += 1;\n\t\titem.timestamp = Date.now();\n\t\tif (value === undefined) {\n\t\t\tdelete item.value;\n\t\t} else {\n\t\t\titem.value = value;\n\t\t}\n\t\tconst update = { rev: this.value.rev, items: { [key]: item } };\n\t\tthis.localUpdate(update);\n\t}\n\n\tpublic clear(): void {\n\t\tthrow new Error(\"Method not implemented.\");\n\t}\n\tpublic delete(key: K): boolean {\n\t\tconst { items } = this.value;\n\t\tconst hasKey = items[key]?.value !== undefined;\n\t\tif (hasKey) {\n\t\t\tthis.countDefined -= 1;\n\t\t\tthis.updateItem(key, undefined);\n\t\t\tthis.emitter.emit(\"localItemRemoved\", { key });\n\t\t}\n\t\treturn hasKey;\n\t}\n\tpublic forEach(\n\t\tcallbackfn: (\n\t\t\tvalue: DeepReadonly<JsonDeserialized<T>>,\n\t\t\tkey: K,\n\t\t\tmap: StateMap<K, T>,\n\t\t) => void,\n\t\tthisArg?: unknown,\n\t): void {\n\t\tfor (const [key, item] of objectEntries(this.value.items)) {\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tcallbackfn(asDeeplyReadonly(item.value), key, this);\n\t\t\t}\n\t\t}\n\t}\n\tpublic get(key: K): DeepReadonly<JsonDeserialized<T>> | undefined {\n\t\treturn asDeeplyReadonly(this.value.items[key]?.value);\n\t}\n\tpublic has(key: K): boolean {\n\t\treturn this.value.items[key]?.value !== undefined;\n\t}\n\tpublic set(key: K, value: JsonSerializable<T> & JsonDeserialized<T>): this {\n\t\tif (!(key in this.value.items)) {\n\t\t\tthis.countDefined += 1;\n\t\t\tthis.value.items[key] = { rev: 0, timestamp: 0, value };\n\t\t}\n\t\tthis.updateItem(key, value);\n\t\tthis.emitter.emit(\"localItemUpdated\", { key, value: asDeeplyReadonly(value) });\n\t\treturn this;\n\t}\n\tpublic get size(): number {\n\t\treturn this.countDefined;\n\t}\n\tpublic keys(): IterableIterator<K> {\n\t\tconst keys: K[] = [];\n\t\tfor (const [key, item] of objectEntries(this.value.items)) {\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tkeys.push(key);\n\t\t\t}\n\t\t}\n\t\treturn keys[Symbol.iterator]();\n\t}\n}\n\n/**\n * State that provides a `Map` of latest known values from this client to\n * others and read access to their values.\n * Entries in the map may vary over time and by client, but all values are expected to\n * be of the same type, which may be a union type.\n *\n * @remarks Create using {@link StateFactory.latestMap} registered to {@link StatesWorkspace}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestMapRaw<T, Keys extends string | number = string | number> {\n\t/**\n\t * Containing {@link Presence}\n\t */\n\treadonly presence: Presence;\n\n\t/**\n\t * Events for LatestMapRaw.\n\t */\n\treadonly events: Listenable<LatestMapRawEvents<T, Keys>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: BroadcastControls;\n\n\t/**\n\t * Current value map for this client.\n\t */\n\treadonly local: StateMap<Keys, T>;\n\t/**\n\t * Iterable access to remote clients' map of values.\n\t */\n\tgetRemotes(): IterableIterator<LatestMapClientData<T, Keys>>;\n\t/**\n\t * Array of {@link Attendee}s that have provided states.\n\t */\n\tgetStateAttendees(): Attendee[];\n\t/**\n\t * Access to a specific client's map of values.\n\t */\n\tgetRemote(attendee: Attendee): ReadonlyMap<Keys, LatestData<T>>;\n}\n\nclass LatestMapRawValueManagerImpl<\n\tT,\n\tRegistrationKey extends string,\n\tKeys extends string | number = string | number,\n> implements\n\t\tLatestMapRaw<T, Keys>,\n\t\tRequired<ValueManager<T, InternalTypes.MapValueState<T, Keys>>>\n{\n\tpublic readonly events = createEmitter<LatestMapRawEvents<T, Keys>>();\n\tpublic readonly controls: OptionalBroadcastControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: RegistrationKey,\n\t\tprivate readonly datastore: StateDatastore<\n\t\t\tRegistrationKey,\n\t\t\tInternalTypes.MapValueState<T, Keys>\n\t\t>,\n\t\tpublic readonly value: InternalTypes.MapValueState<T, Keys>,\n\t\tcontrolSettings: BroadcastControlSettings | undefined,\n\t) {\n\t\tthis.controls = new OptionalBroadcastControl(controlSettings);\n\n\t\tthis.local = new ValueMapImpl<T, Keys>(\n\t\t\tvalue,\n\t\t\tthis.events,\n\t\t\t(updates: InternalTypes.MapValueState<T, Keys>) => {\n\t\t\t\tdatastore.localUpdate(key, updates, {\n\t\t\t\t\tallowableUpdateLatencyMs: this.controls.allowableUpdateLatencyMs,\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t}\n\n\tpublic get presence(): Presence {\n\t\treturn this.datastore.presence;\n\t}\n\n\tpublic readonly local: StateMap<Keys, T>;\n\n\tpublic *getRemotes(): IterableIterator<LatestMapClientData<T, Keys>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const attendeeId of objectKeys(allKnownStates.states)) {\n\t\t\tif (attendeeId !== allKnownStates.self) {\n\t\t\t\tconst attendee = this.datastore.lookupClient(attendeeId);\n\t\t\t\tconst items = this.getRemote(attendee);\n\t\t\t\tyield { attendee, items };\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getStateAttendees(): Attendee[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\treturn objectKeys(allKnownStates.states)\n\t\t\t.filter((attendeeId) => attendeeId !== allKnownStates.self)\n\t\t\t.map((attendeeId) => this.datastore.lookupClient(attendeeId));\n\t}\n\n\tpublic getRemote(attendee: Attendee): ReadonlyMap<Keys, LatestData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst attendeeId = attendee.attendeeId;\n\t\tconst clientStateMap = allKnownStates.states[attendeeId];\n\t\tif (clientStateMap === undefined) {\n\t\t\tthrow new Error(\"No entry for attendee\");\n\t\t}\n\t\tconst items = new Map<Keys, LatestData<T>>();\n\t\tfor (const [key, item] of objectEntries(clientStateMap.items)) {\n\t\t\tconst value = item.value;\n\t\t\tif (value !== undefined) {\n\t\t\t\titems.set(key, {\n\t\t\t\t\tvalue: asDeeplyReadonly(value),\n\t\t\t\t\tmetadata: { revision: item.rev, timestamp: item.timestamp },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn items;\n\t}\n\n\tpublic update<SpecificAttendeeId extends AttendeeId>(\n\t\tattendee: SpecificAttendee<SpecificAttendeeId>,\n\t\t_received: number,\n\t\tvalue: InternalTypes.MapValueState<T, string | number>,\n\t): PostUpdateAction[] {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst attendeeId: SpecificAttendeeId = attendee.attendeeId;\n\t\tconst currentState = (allKnownStates.states[attendeeId] ??=\n\t\t\t// New attendee - prepare new attendee state directory\n\t\t\t{\n\t\t\t\trev: value.rev,\n\t\t\t\titems: {} as unknown as InternalTypes.MapValueState<T, Keys>[\"items\"],\n\t\t\t});\n\t\t// Accumulate individual update keys\n\t\tconst updatedItemKeys: Keys[] = [];\n\t\tfor (const [key, item] of objectEntries(value.items)) {\n\t\t\t// TODO: Key validation needs to be added here.\n\t\t\tconst validKey = key as Keys;\n\t\t\tif (!(key in currentState.items) || currentState.items[validKey].rev < item.rev) {\n\t\t\t\tupdatedItemKeys.push(validKey);\n\t\t\t}\n\t\t}\n\n\t\tif (updatedItemKeys.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Store updates\n\t\tif (value.rev > currentState.rev) {\n\t\t\tcurrentState.rev = value.rev;\n\t\t}\n\t\tconst allUpdates = {\n\t\t\tattendee,\n\t\t\titems: new Map<Keys, LatestData<T>>(),\n\t\t};\n\t\tconst postUpdateActions: PostUpdateAction[] = [];\n\t\tfor (const key of updatedItemKeys) {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\tconst item = value.items[key]!;\n\t\t\tconst hadPriorValue = currentState.items[key]?.value;\n\t\t\tcurrentState.items[key] = item;\n\t\t\tconst metadata = { revision: item.rev, timestamp: item.timestamp };\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tconst itemValue = asDeeplyReadonly(item.value);\n\t\t\t\tconst updatedItem = {\n\t\t\t\t\tattendee,\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue: itemValue,\n\t\t\t\t\tmetadata,\n\t\t\t\t};\n\t\t\t\tpostUpdateActions.push(() => this.events.emit(\"remoteItemUpdated\", updatedItem));\n\t\t\t\tallUpdates.items.set(key, { value: itemValue, metadata });\n\t\t\t} else if (hadPriorValue !== undefined) {\n\t\t\t\tpostUpdateActions.push(() =>\n\t\t\t\t\tthis.events.emit(\"remoteItemRemoved\", {\n\t\t\t\t\t\tattendee,\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmetadata,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tthis.datastore.update(this.key, attendeeId, currentState);\n\t\tpostUpdateActions.push(() => this.events.emit(\"remoteUpdated\", allUpdates));\n\t\treturn postUpdateActions;\n\t}\n}\n\n/**\n * Arguments that are passed to the {@link StateFactory.latestMap} function.\n *\n * @alpha\n */\nexport interface LatestMapArguments<T, Keys extends string | number = string | number> {\n\t/**\n\t * The initial value of the local state.\n\t */\n\tlocal?: {\n\t\t[K in Keys]: JsonSerializable<T> & JsonDeserialized<T>;\n\t};\n\n\t/**\n\t * See {@link BroadcastControlSettings}.\n\t */\n\tsettings?: BroadcastControlSettings | undefined;\n}\n\n/**\n * Factory for creating a {@link LatestMapRaw} State object.\n *\n * @alpha\n */\nexport function latestMap<\n\tT,\n\tKeys extends string | number = string | number,\n\tRegistrationKey extends string = string,\n>(\n\targs?: LatestMapArguments<T, Keys>,\n): InternalTypes.ManagerFactory<\n\tRegistrationKey,\n\tInternalTypes.MapValueState<T, Keys>,\n\tLatestMapRaw<T, Keys>\n> {\n\tconst settings = args?.settings;\n\tconst initialValues = args?.local;\n\n\tconst timestamp = Date.now();\n\tconst value: InternalTypes.MapValueState<\n\t\tT,\n\t\t// This should be `Keys`, but will only work if properties are optional.\n\t\tstring | number\n\t> = { rev: 0, items: {} };\n\t// LatestMapRaw takes ownership of values within initialValues.\n\tif (initialValues !== undefined) {\n\t\tfor (const key of objectKeys(initialValues)) {\n\t\t\tvalue.items[key] = {\n\t\t\t\trev: 0,\n\t\t\t\ttimestamp,\n\t\t\t\tvalue: initialValues[key],\n\t\t\t};\n\t\t}\n\t}\n\tconst factory = (\n\t\tkey: RegistrationKey,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tRegistrationKey,\n\t\t\tInternalTypes.MapValueState<T, Keys>\n\t\t>,\n\t): {\n\t\tinitialData: { value: typeof value; allowableUpdateLatencyMs: number | undefined };\n\t\tmanager: InternalTypes.StateValue<LatestMapRaw<T, Keys>>;\n\t} => ({\n\t\tinitialData: { value, allowableUpdateLatencyMs: settings?.allowableUpdateLatencyMs },\n\t\tmanager: brandIVM<\n\t\t\tLatestMapRawValueManagerImpl<T, RegistrationKey, Keys>,\n\t\t\tT,\n\t\t\tInternalTypes.MapValueState<T, Keys>\n\t\t>(\n\t\t\tnew LatestMapRawValueManagerImpl(\n\t\t\t\tkey,\n\t\t\t\tdatastoreFromHandle(datastoreHandle),\n\t\t\t\tvalue,\n\t\t\t\tsettings,\n\t\t\t),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestMapRawValueManagerImpl });\n}\n"]}
|