@fluidframework/presence 2.10.0-307399

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.
Files changed (255) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -0
  3. package/dist/alpha.d.ts +58 -0
  4. package/dist/baseTypes.d.ts +24 -0
  5. package/dist/baseTypes.d.ts.map +1 -0
  6. package/dist/baseTypes.js +7 -0
  7. package/dist/baseTypes.js.map +1 -0
  8. package/dist/container-definitions/containerExtensions.d.ts +137 -0
  9. package/dist/container-definitions/containerExtensions.d.ts.map +1 -0
  10. package/dist/container-definitions/containerExtensions.js +7 -0
  11. package/dist/container-definitions/containerExtensions.js.map +1 -0
  12. package/dist/container-definitions/index.d.ts +7 -0
  13. package/dist/container-definitions/index.d.ts.map +1 -0
  14. package/dist/container-definitions/index.js +7 -0
  15. package/dist/container-definitions/index.js.map +1 -0
  16. package/dist/container-definitions/runtime.d.ts +12 -0
  17. package/dist/container-definitions/runtime.d.ts.map +1 -0
  18. package/dist/container-definitions/runtime.js +7 -0
  19. package/dist/container-definitions/runtime.js.map +1 -0
  20. package/dist/core-interfaces/exposedUtilityTypes.d.ts +446 -0
  21. package/dist/core-interfaces/exposedUtilityTypes.d.ts.map +1 -0
  22. package/dist/core-interfaces/exposedUtilityTypes.js +11 -0
  23. package/dist/core-interfaces/exposedUtilityTypes.js.map +1 -0
  24. package/dist/core-interfaces/index.d.ts +10 -0
  25. package/dist/core-interfaces/index.d.ts.map +1 -0
  26. package/dist/core-interfaces/index.js +7 -0
  27. package/dist/core-interfaces/index.js.map +1 -0
  28. package/dist/core-interfaces/jsonDeserialized.d.ts +109 -0
  29. package/dist/core-interfaces/jsonDeserialized.d.ts.map +1 -0
  30. package/dist/core-interfaces/jsonDeserialized.js +7 -0
  31. package/dist/core-interfaces/jsonDeserialized.js.map +1 -0
  32. package/dist/core-interfaces/jsonSerializable.d.ts +120 -0
  33. package/dist/core-interfaces/jsonSerializable.d.ts.map +1 -0
  34. package/dist/core-interfaces/jsonSerializable.js +7 -0
  35. package/dist/core-interfaces/jsonSerializable.js.map +1 -0
  36. package/dist/core-interfaces/jsonSerializationErrors.d.ts +31 -0
  37. package/dist/core-interfaces/jsonSerializationErrors.d.ts.map +1 -0
  38. package/dist/core-interfaces/jsonSerializationErrors.js +7 -0
  39. package/dist/core-interfaces/jsonSerializationErrors.js.map +1 -0
  40. package/dist/core-interfaces/jsonType.d.ts +29 -0
  41. package/dist/core-interfaces/jsonType.d.ts.map +1 -0
  42. package/dist/core-interfaces/jsonType.js +7 -0
  43. package/dist/core-interfaces/jsonType.js.map +1 -0
  44. package/dist/datastorePresenceManagerFactory.d.ts +48 -0
  45. package/dist/datastorePresenceManagerFactory.d.ts.map +1 -0
  46. package/dist/datastorePresenceManagerFactory.js +79 -0
  47. package/dist/datastorePresenceManagerFactory.js.map +1 -0
  48. package/dist/datastoreSupport.d.ts +31 -0
  49. package/dist/datastoreSupport.d.ts.map +1 -0
  50. package/dist/datastoreSupport.js +82 -0
  51. package/dist/datastoreSupport.js.map +1 -0
  52. package/dist/events/events.d.ts +198 -0
  53. package/dist/events/events.d.ts.map +1 -0
  54. package/dist/events/events.js +157 -0
  55. package/dist/events/events.js.map +1 -0
  56. package/dist/experimentalAccess.d.ts +15 -0
  57. package/dist/experimentalAccess.d.ts.map +1 -0
  58. package/dist/experimentalAccess.js +46 -0
  59. package/dist/experimentalAccess.js.map +1 -0
  60. package/dist/exposedInternalTypes.d.ts +100 -0
  61. package/dist/exposedInternalTypes.d.ts.map +1 -0
  62. package/dist/exposedInternalTypes.js +19 -0
  63. package/dist/exposedInternalTypes.js.map +1 -0
  64. package/dist/exposedUtilityTypes.d.ts +63 -0
  65. package/dist/exposedUtilityTypes.d.ts.map +1 -0
  66. package/dist/exposedUtilityTypes.js +7 -0
  67. package/dist/exposedUtilityTypes.js.map +1 -0
  68. package/dist/index.d.ts +22 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +21 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/internalTypes.d.ts +39 -0
  73. package/dist/internalTypes.d.ts.map +1 -0
  74. package/dist/internalTypes.js +14 -0
  75. package/dist/internalTypes.js.map +1 -0
  76. package/dist/latestMapValueManager.d.ts +182 -0
  77. package/dist/latestMapValueManager.d.ts.map +1 -0
  78. package/dist/latestMapValueManager.js +206 -0
  79. package/dist/latestMapValueManager.js.map +1 -0
  80. package/dist/latestValueControls.d.ts +44 -0
  81. package/dist/latestValueControls.d.ts.map +1 -0
  82. package/dist/latestValueControls.js +28 -0
  83. package/dist/latestValueControls.js.map +1 -0
  84. package/dist/latestValueManager.d.ts +69 -0
  85. package/dist/latestValueManager.d.ts.map +1 -0
  86. package/dist/latestValueManager.js +100 -0
  87. package/dist/latestValueManager.js.map +1 -0
  88. package/dist/latestValueTypes.d.ts +44 -0
  89. package/dist/latestValueTypes.d.ts.map +1 -0
  90. package/dist/latestValueTypes.js +7 -0
  91. package/dist/latestValueTypes.js.map +1 -0
  92. package/dist/notificationsManager.d.ts +101 -0
  93. package/dist/notificationsManager.d.ts.map +1 -0
  94. package/dist/notificationsManager.js +82 -0
  95. package/dist/notificationsManager.js.map +1 -0
  96. package/dist/package.json +15 -0
  97. package/dist/presence.d.ts +180 -0
  98. package/dist/presence.d.ts.map +1 -0
  99. package/dist/presence.js +23 -0
  100. package/dist/presence.js.map +1 -0
  101. package/dist/presenceDatastoreManager.d.ts +91 -0
  102. package/dist/presenceDatastoreManager.d.ts.map +1 -0
  103. package/dist/presenceDatastoreManager.js +248 -0
  104. package/dist/presenceDatastoreManager.js.map +1 -0
  105. package/dist/presenceManager.d.ts +20 -0
  106. package/dist/presenceManager.d.ts.map +1 -0
  107. package/dist/presenceManager.js +104 -0
  108. package/dist/presenceManager.js.map +1 -0
  109. package/dist/presenceStates.d.ts +78 -0
  110. package/dist/presenceStates.d.ts.map +1 -0
  111. package/dist/presenceStates.js +182 -0
  112. package/dist/presenceStates.js.map +1 -0
  113. package/dist/stateDatastore.d.ts +35 -0
  114. package/dist/stateDatastore.d.ts.map +1 -0
  115. package/dist/stateDatastore.js +26 -0
  116. package/dist/stateDatastore.js.map +1 -0
  117. package/dist/systemWorkspace.d.ts +51 -0
  118. package/dist/systemWorkspace.d.ts.map +1 -0
  119. package/dist/systemWorkspace.js +180 -0
  120. package/dist/systemWorkspace.js.map +1 -0
  121. package/dist/types.d.ts +92 -0
  122. package/dist/types.d.ts.map +1 -0
  123. package/dist/types.js +8 -0
  124. package/dist/types.js.map +1 -0
  125. package/dist/valueManager.d.ts +19 -0
  126. package/dist/valueManager.d.ts.map +1 -0
  127. package/dist/valueManager.js +26 -0
  128. package/dist/valueManager.js.map +1 -0
  129. package/lib/alpha.d.ts +58 -0
  130. package/lib/baseTypes.d.ts +24 -0
  131. package/lib/baseTypes.d.ts.map +1 -0
  132. package/lib/baseTypes.js +6 -0
  133. package/lib/baseTypes.js.map +1 -0
  134. package/lib/container-definitions/containerExtensions.d.ts +137 -0
  135. package/lib/container-definitions/containerExtensions.d.ts.map +1 -0
  136. package/lib/container-definitions/containerExtensions.js +6 -0
  137. package/lib/container-definitions/containerExtensions.js.map +1 -0
  138. package/lib/container-definitions/index.d.ts +7 -0
  139. package/lib/container-definitions/index.d.ts.map +1 -0
  140. package/lib/container-definitions/index.js +6 -0
  141. package/lib/container-definitions/index.js.map +1 -0
  142. package/lib/container-definitions/runtime.d.ts +12 -0
  143. package/lib/container-definitions/runtime.d.ts.map +1 -0
  144. package/lib/container-definitions/runtime.js +6 -0
  145. package/lib/container-definitions/runtime.js.map +1 -0
  146. package/lib/core-interfaces/exposedUtilityTypes.d.ts +446 -0
  147. package/lib/core-interfaces/exposedUtilityTypes.d.ts.map +1 -0
  148. package/lib/core-interfaces/exposedUtilityTypes.js +10 -0
  149. package/lib/core-interfaces/exposedUtilityTypes.js.map +1 -0
  150. package/lib/core-interfaces/index.d.ts +10 -0
  151. package/lib/core-interfaces/index.d.ts.map +1 -0
  152. package/lib/core-interfaces/index.js +6 -0
  153. package/lib/core-interfaces/index.js.map +1 -0
  154. package/lib/core-interfaces/jsonDeserialized.d.ts +109 -0
  155. package/lib/core-interfaces/jsonDeserialized.d.ts.map +1 -0
  156. package/lib/core-interfaces/jsonDeserialized.js +6 -0
  157. package/lib/core-interfaces/jsonDeserialized.js.map +1 -0
  158. package/lib/core-interfaces/jsonSerializable.d.ts +120 -0
  159. package/lib/core-interfaces/jsonSerializable.d.ts.map +1 -0
  160. package/lib/core-interfaces/jsonSerializable.js +6 -0
  161. package/lib/core-interfaces/jsonSerializable.js.map +1 -0
  162. package/lib/core-interfaces/jsonSerializationErrors.d.ts +31 -0
  163. package/lib/core-interfaces/jsonSerializationErrors.d.ts.map +1 -0
  164. package/lib/core-interfaces/jsonSerializationErrors.js +6 -0
  165. package/lib/core-interfaces/jsonSerializationErrors.js.map +1 -0
  166. package/lib/core-interfaces/jsonType.d.ts +29 -0
  167. package/lib/core-interfaces/jsonType.d.ts.map +1 -0
  168. package/lib/core-interfaces/jsonType.js +6 -0
  169. package/lib/core-interfaces/jsonType.js.map +1 -0
  170. package/lib/datastorePresenceManagerFactory.d.ts +48 -0
  171. package/lib/datastorePresenceManagerFactory.d.ts.map +1 -0
  172. package/lib/datastorePresenceManagerFactory.js +75 -0
  173. package/lib/datastorePresenceManagerFactory.js.map +1 -0
  174. package/lib/datastoreSupport.d.ts +31 -0
  175. package/lib/datastoreSupport.d.ts.map +1 -0
  176. package/lib/datastoreSupport.js +77 -0
  177. package/lib/datastoreSupport.js.map +1 -0
  178. package/lib/events/events.d.ts +198 -0
  179. package/lib/events/events.d.ts.map +1 -0
  180. package/lib/events/events.js +152 -0
  181. package/lib/events/events.js.map +1 -0
  182. package/lib/experimentalAccess.d.ts +15 -0
  183. package/lib/experimentalAccess.d.ts.map +1 -0
  184. package/lib/experimentalAccess.js +42 -0
  185. package/lib/experimentalAccess.js.map +1 -0
  186. package/lib/exposedInternalTypes.d.ts +100 -0
  187. package/lib/exposedInternalTypes.d.ts.map +1 -0
  188. package/lib/exposedInternalTypes.js +16 -0
  189. package/lib/exposedInternalTypes.js.map +1 -0
  190. package/lib/exposedUtilityTypes.d.ts +63 -0
  191. package/lib/exposedUtilityTypes.d.ts.map +1 -0
  192. package/lib/exposedUtilityTypes.js +6 -0
  193. package/lib/exposedUtilityTypes.js.map +1 -0
  194. package/lib/index.d.ts +22 -0
  195. package/lib/index.d.ts.map +1 -0
  196. package/lib/index.js +11 -0
  197. package/lib/index.js.map +1 -0
  198. package/lib/internalTypes.d.ts +39 -0
  199. package/lib/internalTypes.d.ts.map +1 -0
  200. package/lib/internalTypes.js +11 -0
  201. package/lib/internalTypes.js.map +1 -0
  202. package/lib/latestMapValueManager.d.ts +182 -0
  203. package/lib/latestMapValueManager.d.ts.map +1 -0
  204. package/lib/latestMapValueManager.js +202 -0
  205. package/lib/latestMapValueManager.js.map +1 -0
  206. package/lib/latestValueControls.d.ts +44 -0
  207. package/lib/latestValueControls.d.ts.map +1 -0
  208. package/lib/latestValueControls.js +24 -0
  209. package/lib/latestValueControls.js.map +1 -0
  210. package/lib/latestValueManager.d.ts +69 -0
  211. package/lib/latestValueManager.d.ts.map +1 -0
  212. package/lib/latestValueManager.js +96 -0
  213. package/lib/latestValueManager.js.map +1 -0
  214. package/lib/latestValueTypes.d.ts +44 -0
  215. package/lib/latestValueTypes.d.ts.map +1 -0
  216. package/lib/latestValueTypes.js +6 -0
  217. package/lib/latestValueTypes.js.map +1 -0
  218. package/lib/notificationsManager.d.ts +101 -0
  219. package/lib/notificationsManager.d.ts.map +1 -0
  220. package/lib/notificationsManager.js +78 -0
  221. package/lib/notificationsManager.js.map +1 -0
  222. package/lib/presence.d.ts +180 -0
  223. package/lib/presence.d.ts.map +1 -0
  224. package/lib/presence.js +20 -0
  225. package/lib/presence.js.map +1 -0
  226. package/lib/presenceDatastoreManager.d.ts +91 -0
  227. package/lib/presenceDatastoreManager.d.ts.map +1 -0
  228. package/lib/presenceDatastoreManager.js +244 -0
  229. package/lib/presenceDatastoreManager.js.map +1 -0
  230. package/lib/presenceManager.d.ts +20 -0
  231. package/lib/presenceManager.d.ts.map +1 -0
  232. package/lib/presenceManager.js +100 -0
  233. package/lib/presenceManager.js.map +1 -0
  234. package/lib/presenceStates.d.ts +78 -0
  235. package/lib/presenceStates.d.ts.map +1 -0
  236. package/lib/presenceStates.js +177 -0
  237. package/lib/presenceStates.js.map +1 -0
  238. package/lib/stateDatastore.d.ts +35 -0
  239. package/lib/stateDatastore.d.ts.map +1 -0
  240. package/lib/stateDatastore.js +21 -0
  241. package/lib/stateDatastore.js.map +1 -0
  242. package/lib/systemWorkspace.d.ts +51 -0
  243. package/lib/systemWorkspace.d.ts.map +1 -0
  244. package/lib/systemWorkspace.js +176 -0
  245. package/lib/systemWorkspace.js.map +1 -0
  246. package/lib/tsdoc-metadata.json +11 -0
  247. package/lib/types.d.ts +92 -0
  248. package/lib/types.d.ts.map +1 -0
  249. package/lib/types.js +7 -0
  250. package/lib/types.js.map +1 -0
  251. package/lib/valueManager.d.ts +19 -0
  252. package/lib/valueManager.d.ts.map +1 -0
  253. package/lib/valueManager.js +21 -0
  254. package/lib/valueManager.js.map +1 -0
  255. package/package.json +175 -0
@@ -0,0 +1,202 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { LatestValueControl } from "./latestValueControls.js";
6
+ import { datastoreFromHandle } from "./stateDatastore.js";
7
+ import { brandIVM } from "./valueManager.js";
8
+ import { createEmitter } from "@fluidframework/presence/internal/events";
9
+ class ValueMapImpl {
10
+ constructor(value, localUpdate) {
11
+ this.value = value;
12
+ this.localUpdate = localUpdate;
13
+ // All initial items are expected to be defined.
14
+ // TODO assert all defined and/or update type.
15
+ this.countDefined = Object.keys(value.items).length;
16
+ }
17
+ updateItem(key, value) {
18
+ this.value.rev += 1;
19
+ const item = this.value.items[key];
20
+ item.rev += 1;
21
+ item.timestamp = Date.now();
22
+ if (value === undefined) {
23
+ delete item.value;
24
+ }
25
+ else {
26
+ item.value = value;
27
+ }
28
+ const update = { rev: this.value.rev, items: { [key]: item } };
29
+ this.localUpdate(update, /* forceUpdate */ false);
30
+ }
31
+ clear() {
32
+ throw new Error("Method not implemented.");
33
+ }
34
+ delete(key) {
35
+ const { items } = this.value;
36
+ const hasKey = items[key]?.value !== undefined;
37
+ if (hasKey) {
38
+ this.countDefined -= 1;
39
+ this.updateItem(key, undefined);
40
+ }
41
+ return hasKey;
42
+ }
43
+ forEach(callbackfn, thisArg) {
44
+ for (const [key, item] of Object.entries(this.value.items)) {
45
+ if (item.value !== undefined) {
46
+ // TODO: see about typing InternalTypes.MapValueState with K
47
+ callbackfn(item.value, key, this);
48
+ }
49
+ }
50
+ }
51
+ get(key) {
52
+ return this.value.items[key]?.value;
53
+ }
54
+ has(key) {
55
+ return this.value.items[key]?.value !== undefined;
56
+ }
57
+ set(key, value) {
58
+ if (!(key in this.value.items)) {
59
+ this.countDefined += 1;
60
+ this.value.items[key] = { rev: 0, timestamp: 0, value };
61
+ }
62
+ this.updateItem(key, value);
63
+ return this;
64
+ }
65
+ get size() {
66
+ return this.countDefined;
67
+ }
68
+ keys() {
69
+ const keys = [];
70
+ for (const [key, item] of Object.entries(this.value.items)) {
71
+ if (item.value !== undefined) {
72
+ keys.push(key);
73
+ }
74
+ }
75
+ return keys[Symbol.iterator]();
76
+ }
77
+ }
78
+ class LatestMapValueManagerImpl {
79
+ constructor(key, datastore, value, controlSettings) {
80
+ this.key = key;
81
+ this.datastore = datastore;
82
+ this.value = value;
83
+ this.events = createEmitter();
84
+ this.controls = new LatestValueControl(controlSettings);
85
+ this.local = new ValueMapImpl(value, (updates, forceUpdate) => {
86
+ datastore.localUpdate(key, updates, forceUpdate);
87
+ });
88
+ }
89
+ *clientValues() {
90
+ const allKnownStates = this.datastore.knownValues(this.key);
91
+ for (const clientSessionId of Object.keys(allKnownStates.states)) {
92
+ if (clientSessionId !== allKnownStates.self) {
93
+ const client = this.datastore.lookupClient(clientSessionId);
94
+ const items = this.clientValue(client);
95
+ yield { client, items };
96
+ }
97
+ }
98
+ }
99
+ clients() {
100
+ const allKnownStates = this.datastore.knownValues(this.key);
101
+ return Object.keys(allKnownStates.states)
102
+ .filter((clientSessionId) => clientSessionId !== allKnownStates.self)
103
+ .map((clientSessionId) => this.datastore.lookupClient(clientSessionId));
104
+ }
105
+ clientValue(client) {
106
+ const allKnownStates = this.datastore.knownValues(this.key);
107
+ const clientSessionId = client.sessionId;
108
+ if (!(clientSessionId in allKnownStates.states)) {
109
+ throw new Error("No entry for client");
110
+ }
111
+ const clientStateMap = allKnownStates.states[clientSessionId];
112
+ const items = new Map();
113
+ for (const [key, item] of Object.entries(clientStateMap.items)) {
114
+ const value = item.value;
115
+ if (value !== undefined) {
116
+ items.set(key, {
117
+ value,
118
+ metadata: { revision: item.rev, timestamp: item.timestamp },
119
+ });
120
+ }
121
+ }
122
+ return items;
123
+ }
124
+ update(client, _received, value) {
125
+ const allKnownStates = this.datastore.knownValues(this.key);
126
+ const clientSessionId = client.sessionId;
127
+ if (!(clientSessionId in allKnownStates.states)) {
128
+ // New client - prepare new client state directory
129
+ allKnownStates.states[clientSessionId] = { rev: value.rev, items: {} };
130
+ }
131
+ const currentState = allKnownStates.states[clientSessionId];
132
+ // Accumulate individual update keys
133
+ const updatedItemKeys = [];
134
+ for (const [key, item] of Object.entries(value.items)) {
135
+ if (!(key in currentState.items) || currentState.items[key].rev < item.rev) {
136
+ updatedItemKeys.push(key);
137
+ }
138
+ }
139
+ if (updatedItemKeys.length === 0) {
140
+ return;
141
+ }
142
+ // Store updates
143
+ if (value.rev > currentState.rev) {
144
+ currentState.rev = value.rev;
145
+ }
146
+ const allUpdates = {
147
+ client,
148
+ items: new Map(),
149
+ };
150
+ for (const key of updatedItemKeys) {
151
+ const item = value.items[key];
152
+ const hadPriorValue = currentState.items[key]?.value;
153
+ currentState.items[key] = item;
154
+ const metadata = { revision: item.rev, timestamp: item.timestamp };
155
+ if (item.value !== undefined) {
156
+ this.events.emit("itemUpdated", {
157
+ client,
158
+ key,
159
+ value: item.value,
160
+ metadata,
161
+ });
162
+ allUpdates.items.set(key, { value: item.value, metadata });
163
+ }
164
+ else if (hadPriorValue !== undefined) {
165
+ this.events.emit("itemRemoved", {
166
+ client,
167
+ key,
168
+ metadata,
169
+ });
170
+ }
171
+ }
172
+ this.datastore.update(this.key, clientSessionId, currentState);
173
+ this.events.emit("updated", allUpdates);
174
+ }
175
+ }
176
+ /**
177
+ * Factory for creating a {@link LatestMapValueManager}.
178
+ *
179
+ * @alpha
180
+ */
181
+ export function LatestMap(initialValues, controls) {
182
+ const timestamp = Date.now();
183
+ const value = { rev: 0, items: {} };
184
+ // LatestMapValueManager takes ownership of values within initialValues.
185
+ if (initialValues !== undefined) {
186
+ for (const key of Object.keys(initialValues)) {
187
+ value.items[key] = { rev: 0, timestamp, value: initialValues[key] };
188
+ }
189
+ }
190
+ const controlSettings = controls
191
+ ? { ...controls }
192
+ : {
193
+ allowableUpdateLatency: 60,
194
+ forcedRefreshInterval: 0,
195
+ };
196
+ const factory = (key, datastoreHandle) => ({
197
+ value,
198
+ manager: brandIVM(new LatestMapValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, controlSettings)),
199
+ });
200
+ return Object.assign(factory, { instanceBase: LatestMapValueManagerImpl });
201
+ }
202
+ //# sourceMappingURL=latestMapValueManager.js.map
@@ -0,0 +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 type { ValueManager } from \"./internalTypes.js\";\nimport type { LatestValueControls } from \"./latestValueControls.js\";\nimport { LatestValueControl } from \"./latestValueControls.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\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { ISubscribable } from \"@fluidframework/presence/internal/events\";\nimport { createEmitter } from \"@fluidframework/presence/internal/events\";\nimport type { InternalTypes } from \"@fluidframework/presence/internal/exposedInternalTypes\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\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 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 is removed.\n\t * @param removedItem - Removed item.\n\t *\n\t * @eventProperty\n\t */\n\titemRemoved: (removedItem: LatestMapItemRemovedClientData<K>) => 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>,\n\t\tprivate readonly localUpdate: (\n\t\t\tupdates: InternalTypes.MapValueState<T>,\n\t\t\tforceUpdate: boolean,\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\tprivate updateItem(key: K, value: InternalTypes.ValueOptionalState<T>[\"value\"]): void {\n\t\tthis.value.rev += 1;\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, /* forceUpdate */ false);\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}\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 Object.entries(this.value.items)) {\n\t\t\tif (item.value !== undefined) {\n\t\t\t\t// TODO: see about typing InternalTypes.MapValueState with K\n\t\t\t\tcallbackfn(item.value, key as K, 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\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 Object.entries(this.value.items)) {\n\t\t\tif (item.value !== undefined) {\n\t\t\t\tkeys.push(key as K);\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: ISubscribable<LatestMapValueManagerEvents<T, Keys>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: LatestValueControls;\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 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>>>\n{\n\tpublic readonly events = createEmitter<LatestMapValueManagerEvents<T, Keys>>();\n\tpublic readonly controls: LatestValueControl;\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>\n\t\t>,\n\t\tpublic readonly value: InternalTypes.MapValueState<T>,\n\t\tcontrolSettings: LatestValueControls,\n\t) {\n\t\tthis.controls = new LatestValueControl(controlSettings);\n\n\t\tthis.local = new ValueMapImpl<T, Keys>(\n\t\t\tvalue,\n\t\t\t(updates: InternalTypes.MapValueState<T>, forceUpdate: boolean) => {\n\t\t\t\tdatastore.localUpdate(key, updates, forceUpdate);\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 Object.keys(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 Object.keys(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\tif (!(clientSessionId in allKnownStates.states)) {\n\t\t\tthrow new Error(\"No entry for client\");\n\t\t}\n\t\tconst clientStateMap = allKnownStates.states[clientSessionId];\n\t\tconst items = new Map<Keys, LatestValueData<T>>();\n\t\tfor (const [key, item] of Object.entries(clientStateMap.items)) {\n\t\t\tconst value = item.value;\n\t\t\tif (value !== undefined) {\n\t\t\t\titems.set(key as Keys, {\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>,\n\t): void {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId: SpecificSessionClientId = client.sessionId;\n\t\tif (!(clientSessionId in allKnownStates.states)) {\n\t\t\t// New client - prepare new client state directory\n\t\t\tallKnownStates.states[clientSessionId] = { rev: value.rev, items: {} };\n\t\t}\n\t\tconst currentState = allKnownStates.states[clientSessionId];\n\t\t// Accumulate individual update keys\n\t\tconst updatedItemKeys: Keys[] = [];\n\t\tfor (const [key, item] of Object.entries(value.items)) {\n\t\t\tif (!(key in currentState.items) || currentState.items[key].rev < item.rev) {\n\t\t\t\tupdatedItemKeys.push(key as Keys);\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\tfor (const key of updatedItemKeys) {\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\tthis.events.emit(\"itemUpdated\", {\n\t\t\t\t\tclient,\n\t\t\t\t\tkey,\n\t\t\t\t\tvalue: item.value,\n\t\t\t\t\tmetadata,\n\t\t\t\t});\n\t\t\t\tallUpdates.items.set(key, { value: item.value, metadata });\n\t\t\t} else if (hadPriorValue !== undefined) {\n\t\t\t\tthis.events.emit(\"itemRemoved\", {\n\t\t\t\t\tclient,\n\t\t\t\t\tkey,\n\t\t\t\t\tmetadata,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, currentState);\n\t\tthis.events.emit(\"updated\", allUpdates);\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?: LatestValueControls,\n): InternalTypes.ManagerFactory<\n\tRegistrationKey,\n\tInternalTypes.MapValueState<T>,\n\tLatestMapValueManager<T, Keys>\n> {\n\tconst timestamp = Date.now();\n\tconst value: InternalTypes.MapValueState<T> = { rev: 0, items: {} };\n\t// LatestMapValueManager takes ownership of values within initialValues.\n\tif (initialValues !== undefined) {\n\t\tfor (const key of Object.keys(initialValues)) {\n\t\t\tvalue.items[key] = { rev: 0, timestamp, value: initialValues[key as Keys] };\n\t\t}\n\t}\n\tconst controlSettings = controls\n\t\t? { ...controls }\n\t\t: {\n\t\t\t\tallowableUpdateLatency: 60,\n\t\t\t\tforcedRefreshInterval: 0,\n\t\t\t};\n\tconst factory = (\n\t\tkey: RegistrationKey,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tRegistrationKey,\n\t\t\tInternalTypes.MapValueState<T>\n\t\t>,\n\t): {\n\t\tvalue: typeof value;\n\t\tmanager: InternalTypes.StateValue<LatestMapValueManager<T, Keys>>;\n\t} => ({\n\t\tvalue,\n\t\tmanager: brandIVM<\n\t\t\tLatestMapValueManagerImpl<T, RegistrationKey, Keys>,\n\t\t\tT,\n\t\t\tInternalTypes.MapValueState<T>\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\tcontrolSettings,\n\t\t\t),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestMapValueManagerImpl });\n}\n"]}
@@ -0,0 +1,44 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /**
6
+ * Common controls for the Latest* Value Managers.
7
+ *
8
+ * @alpha
9
+ */
10
+ export interface LatestValueControls {
11
+ /**
12
+ * Maximum time in milliseconds that a local value update is allowed
13
+ * to remain pending before it must be broadcast.
14
+ *
15
+ * @remarks There is no guarantee of broadcast within time allowed
16
+ * as other conditions such as disconnect or service throttling may
17
+ * cause a delay.
18
+ */
19
+ allowableUpdateLatency: number;
20
+ /**
21
+ * Target time in milliseconds between oldest changed local state
22
+ * has been broadcast and forced rebroadcast of all local values.
23
+ * A value of less than 10 disables forced refresh.
24
+ *
25
+ * @defaultValue 0
26
+ *
27
+ * @privateRemarks
28
+ * Any time less than 10 milliseconds is likely to generate too
29
+ * many signals. Ideally this feature becomes obsolete as
30
+ * we understand the system better and account for holes.
31
+ */
32
+ forcedRefreshInterval: number;
33
+ }
34
+ /**
35
+ * @internal
36
+ */
37
+ export declare class LatestValueControl implements LatestValueControls {
38
+ allowableUpdateLatency: number;
39
+ private _forcedRefreshInterval;
40
+ constructor(settings: LatestValueControls);
41
+ get forcedRefreshInterval(): number;
42
+ set forcedRefreshInterval(value: number);
43
+ }
44
+ //# sourceMappingURL=latestValueControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestValueControls.d.ts","sourceRoot":"","sources":["../src/latestValueControls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;;OAOG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAE/B;;;;;;;;;;;OAWG;IACH,qBAAqB,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IACtD,sBAAsB,EAAE,MAAM,CAAC;IACtC,OAAO,CAAC,sBAAsB,CAAS;gBAEpB,QAAQ,EAAE,mBAAmB;IAKhD,IAAW,qBAAqB,IAAI,MAAM,CAEzC;IACD,IAAW,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAM7C;CACD"}
@@ -0,0 +1,24 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /**
6
+ * @internal
7
+ */
8
+ export class LatestValueControl {
9
+ constructor(settings) {
10
+ this.allowableUpdateLatency = settings.allowableUpdateLatency;
11
+ this._forcedRefreshInterval = settings.forcedRefreshInterval;
12
+ }
13
+ get forcedRefreshInterval() {
14
+ return this._forcedRefreshInterval;
15
+ }
16
+ set forcedRefreshInterval(value) {
17
+ this._forcedRefreshInterval = value < 10 ? 0 : value;
18
+ if (this._forcedRefreshInterval >= 10) {
19
+ // TODO: enable periodic forced refresh
20
+ throw new Error("Forced Refresh feature is not implemented");
21
+ }
22
+ }
23
+ }
24
+ //# sourceMappingURL=latestValueControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestValueControls.js","sourceRoot":"","sources":["../src/latestValueControls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiCH;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAI9B,YAAmB,QAA6B;QAC/C,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,sBAAsB,CAAC;QAC9D,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAC9D,CAAC;IAED,IAAW,qBAAqB;QAC/B,OAAO,IAAI,CAAC,sBAAsB,CAAC;IACpC,CAAC;IACD,IAAW,qBAAqB,CAAC,KAAa;QAC7C,IAAI,CAAC,sBAAsB,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACrD,IAAI,IAAI,CAAC,sBAAsB,IAAI,EAAE,EAAE,CAAC;YACvC,uCAAuC;YACvC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC9D,CAAC;IACF,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * Common controls for the Latest* Value Managers.\n *\n * @alpha\n */\nexport interface LatestValueControls {\n\t/**\n\t * Maximum time in milliseconds that a local value update is allowed\n\t * to remain pending before it must be broadcast.\n\t *\n\t * @remarks There is no guarantee of broadcast within time allowed\n\t * as other conditions such as disconnect or service throttling may\n\t * cause a delay.\n\t */\n\tallowableUpdateLatency: number;\n\n\t/**\n\t * Target time in milliseconds between oldest changed local state\n\t * has been broadcast and forced rebroadcast of all local values.\n\t * A value of less than 10 disables forced refresh.\n\t *\n\t * @defaultValue 0\n\t *\n\t * @privateRemarks\n\t * Any time less than 10 milliseconds is likely to generate too\n\t * many signals. Ideally this feature becomes obsolete as\n\t * we understand the system better and account for holes.\n\t */\n\tforcedRefreshInterval: number;\n}\n\n/**\n * @internal\n */\nexport class LatestValueControl implements LatestValueControls {\n\tpublic allowableUpdateLatency: number;\n\tprivate _forcedRefreshInterval: number;\n\n\tpublic constructor(settings: LatestValueControls) {\n\t\tthis.allowableUpdateLatency = settings.allowableUpdateLatency;\n\t\tthis._forcedRefreshInterval = settings.forcedRefreshInterval;\n\t}\n\n\tpublic get forcedRefreshInterval(): number {\n\t\treturn this._forcedRefreshInterval;\n\t}\n\tpublic set forcedRefreshInterval(value: number) {\n\t\tthis._forcedRefreshInterval = value < 10 ? 0 : value;\n\t\tif (this._forcedRefreshInterval >= 10) {\n\t\t\t// TODO: enable periodic forced refresh\n\t\t\tthrow new Error(\"Forced Refresh feature is not implemented\");\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,69 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import type { LatestValueControls } from "./latestValueControls.js";
6
+ import type { LatestValueClientData, LatestValueData } from "./latestValueTypes.js";
7
+ import type { ISessionClient } from "./presence.js";
8
+ import type { JsonDeserialized, JsonSerializable } from "@fluidframework/presence/internal/core-interfaces";
9
+ import type { ISubscribable } from "@fluidframework/presence/internal/events";
10
+ import type { InternalTypes } from "@fluidframework/presence/internal/exposedInternalTypes";
11
+ import type { InternalUtilityTypes } from "@fluidframework/presence/internal/exposedUtilityTypes";
12
+ /**
13
+ * @sealed
14
+ * @alpha
15
+ */
16
+ export interface LatestValueManagerEvents<T> {
17
+ /**
18
+ * Raised when remote client's value is updated, which may be the same value.
19
+ *
20
+ * @eventProperty
21
+ */
22
+ updated: (update: LatestValueClientData<T>) => void;
23
+ }
24
+ /**
25
+ * Value manager that provides the latest known value from this client to others and read access to their values.
26
+ * All participant clients must provide a value.
27
+ *
28
+ * @remarks Create using {@link Latest} registered to {@link PresenceStates}.
29
+ *
30
+ * @sealed
31
+ * @alpha
32
+ */
33
+ export interface LatestValueManager<T> {
34
+ /**
35
+ * Events for Latest value manager.
36
+ */
37
+ readonly events: ISubscribable<LatestValueManagerEvents<T>>;
38
+ /**
39
+ * Controls for management of sending updates.
40
+ */
41
+ readonly controls: LatestValueControls;
42
+ /**
43
+ * Current state for this client.
44
+ * State for this client that will be transmitted to all other connected clients.
45
+ * @remarks Manager assumes ownership of the value and its references. Make a deep clone before
46
+ * setting, if needed. No comparison is done to detect changes; all sets are transmitted.
47
+ */
48
+ get local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;
49
+ set local(value: JsonSerializable<T> & JsonDeserialized<T>);
50
+ /**
51
+ * Iterable access to remote clients' values.
52
+ */
53
+ clientValues(): IterableIterator<LatestValueClientData<T>>;
54
+ /**
55
+ * Array of known clients.
56
+ */
57
+ clients(): ISessionClient[];
58
+ /**
59
+ * Access to a specific client's value.
60
+ */
61
+ clientValue(client: ISessionClient): LatestValueData<T>;
62
+ }
63
+ /**
64
+ * Factory for creating a {@link LatestValueManager}.
65
+ *
66
+ * @alpha
67
+ */
68
+ export declare function Latest<T extends object, Key extends string = string>(initialValue: JsonSerializable<T> & JsonDeserialized<T> & object, controls?: LatestValueControls): InternalTypes.ManagerFactory<Key, InternalTypes.ValueRequiredState<T>, LatestValueManager<T>>;
69
+ //# sourceMappingURL=latestValueManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestValueManager.d.ts","sourceRoot":"","sources":["../src/latestValueManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAIpD,OAAO,KAAK,EACX,gBAAgB,EAChB,gBAAgB,EAChB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAE9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wDAAwD,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAElG;;;GAGG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IAC1C;;;;OAIG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5D;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IAEvC;;;;;OAKG;IACH,IAAI,KAAK,IAAI,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE;IAE5D;;OAEG;IACH,YAAY,IAAI,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D;;OAEG;IACH,OAAO,IAAI,cAAc,EAAE,CAAC;IAC5B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;CACxD;AAkFD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,GAAG,MAAM,EACnE,YAAY,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,EAChE,QAAQ,CAAC,EAAE,mBAAmB,GAC5B,aAAa,CAAC,cAAc,CAC9B,GAAG,EACH,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,EACnC,kBAAkB,CAAC,CAAC,CAAC,CACrB,CAmCA"}
@@ -0,0 +1,96 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { brandedObjectEntries } from "./internalTypes.js";
6
+ import { LatestValueControl } from "./latestValueControls.js";
7
+ import { datastoreFromHandle } from "./stateDatastore.js";
8
+ import { brandIVM } from "./valueManager.js";
9
+ import { createEmitter } from "@fluidframework/presence/internal/events";
10
+ class LatestValueManagerImpl {
11
+ constructor(key, datastore, value, controlSettings) {
12
+ this.key = key;
13
+ this.datastore = datastore;
14
+ this.value = value;
15
+ this.events = createEmitter();
16
+ this.controls = new LatestValueControl(controlSettings);
17
+ }
18
+ get local() {
19
+ return this.value.value;
20
+ }
21
+ set local(value) {
22
+ this.value.rev += 1;
23
+ this.value.timestamp = Date.now();
24
+ this.value.value = value;
25
+ this.datastore.localUpdate(this.key, this.value, /* forceUpdate */ false);
26
+ }
27
+ *clientValues() {
28
+ const allKnownStates = this.datastore.knownValues(this.key);
29
+ for (const [clientSessionId, value] of brandedObjectEntries(allKnownStates.states)) {
30
+ if (clientSessionId !== allKnownStates.self) {
31
+ yield {
32
+ client: this.datastore.lookupClient(clientSessionId),
33
+ value: value.value,
34
+ metadata: { revision: value.rev, timestamp: value.timestamp },
35
+ };
36
+ }
37
+ }
38
+ }
39
+ clients() {
40
+ const allKnownStates = this.datastore.knownValues(this.key);
41
+ return Object.keys(allKnownStates.states)
42
+ .filter((clientSessionId) => clientSessionId !== allKnownStates.self)
43
+ .map((clientSessionId) => this.datastore.lookupClient(clientSessionId));
44
+ }
45
+ clientValue(client) {
46
+ const allKnownStates = this.datastore.knownValues(this.key);
47
+ const clientSessionId = client.sessionId;
48
+ if (clientSessionId in allKnownStates.states) {
49
+ const { value, rev: revision } = allKnownStates.states[clientSessionId];
50
+ return { value, metadata: { revision, timestamp: Date.now() } };
51
+ }
52
+ throw new Error("No entry for clientId");
53
+ }
54
+ update(client, _received, value) {
55
+ const allKnownStates = this.datastore.knownValues(this.key);
56
+ const clientSessionId = client.sessionId;
57
+ if (clientSessionId in allKnownStates.states) {
58
+ const currentState = allKnownStates.states[clientSessionId];
59
+ if (currentState.rev >= value.rev) {
60
+ return;
61
+ }
62
+ }
63
+ this.datastore.update(this.key, clientSessionId, value);
64
+ this.events.emit("updated", {
65
+ client,
66
+ value: value.value,
67
+ metadata: { revision: value.rev, timestamp: value.timestamp },
68
+ });
69
+ }
70
+ }
71
+ /**
72
+ * Factory for creating a {@link LatestValueManager}.
73
+ *
74
+ * @alpha
75
+ */
76
+ export function Latest(initialValue, controls) {
77
+ // LatestValueManager takes ownership of initialValue but makes a shallow
78
+ // copy for basic protection.
79
+ const value = {
80
+ rev: 0,
81
+ timestamp: Date.now(),
82
+ value: { ...initialValue },
83
+ };
84
+ const controlSettings = controls
85
+ ? { ...controls }
86
+ : {
87
+ allowableUpdateLatency: 60,
88
+ forcedRefreshInterval: 0,
89
+ };
90
+ const factory = (key, datastoreHandle) => ({
91
+ value,
92
+ manager: brandIVM(new LatestValueManagerImpl(key, datastoreFromHandle(datastoreHandle), value, controlSettings)),
93
+ });
94
+ return Object.assign(factory, { instanceBase: LatestValueManagerImpl });
95
+ }
96
+ //# sourceMappingURL=latestValueManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestValueManager.js","sourceRoot":"","sources":["../src/latestValueManager.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 type { ValueManager } from \"./internalTypes.js\";\nimport { brandedObjectEntries } from \"./internalTypes.js\";\nimport type { LatestValueControls } from \"./latestValueControls.js\";\nimport { LatestValueControl } from \"./latestValueControls.js\";\nimport type { LatestValueClientData, LatestValueData } from \"./latestValueTypes.js\";\nimport type { ISessionClient } from \"./presence.js\";\nimport { datastoreFromHandle, type StateDatastore } from \"./stateDatastore.js\";\nimport { brandIVM } from \"./valueManager.js\";\n\nimport type {\n\tJsonDeserialized,\n\tJsonSerializable,\n} from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { ISubscribable } from \"@fluidframework/presence/internal/events\";\nimport { createEmitter } from \"@fluidframework/presence/internal/events\";\nimport type { InternalTypes } from \"@fluidframework/presence/internal/exposedInternalTypes\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\n\n/**\n * @sealed\n * @alpha\n */\nexport interface LatestValueManagerEvents<T> {\n\t/**\n\t * Raised when remote client's value is updated, which may be the same value.\n\t *\n\t * @eventProperty\n\t */\n\tupdated: (update: LatestValueClientData<T>) => void;\n}\n\n/**\n * Value manager that provides the latest known value from this client to others and read access to their values.\n * All participant clients must provide a value.\n *\n * @remarks Create using {@link Latest} registered to {@link PresenceStates}.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueManager<T> {\n\t/**\n\t * Events for Latest value manager.\n\t */\n\treadonly events: ISubscribable<LatestValueManagerEvents<T>>;\n\n\t/**\n\t * Controls for management of sending updates.\n\t */\n\treadonly controls: LatestValueControls;\n\n\t/**\n\t * Current state for this client.\n\t * State for this client that will be transmitted to all other connected clients.\n\t * @remarks Manager assumes ownership of the value and its references. Make a deep clone before\n\t * setting, if needed. No comparison is done to detect changes; all sets are transmitted.\n\t */\n\tget local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;\n\tset local(value: JsonSerializable<T> & JsonDeserialized<T>);\n\n\t/**\n\t * Iterable access to remote clients' values.\n\t */\n\tclientValues(): IterableIterator<LatestValueClientData<T>>;\n\t/**\n\t * Array of known clients.\n\t */\n\tclients(): ISessionClient[];\n\t/**\n\t * Access to a specific client's value.\n\t */\n\tclientValue(client: ISessionClient): LatestValueData<T>;\n}\n\nclass LatestValueManagerImpl<T, Key extends string>\n\timplements\n\t\tLatestValueManager<T>,\n\t\tRequired<ValueManager<T, InternalTypes.ValueRequiredState<T>>>\n{\n\tpublic readonly events = createEmitter<LatestValueManagerEvents<T>>();\n\tpublic readonly controls: LatestValueControl;\n\n\tpublic constructor(\n\t\tprivate readonly key: Key,\n\t\tprivate readonly datastore: StateDatastore<Key, InternalTypes.ValueRequiredState<T>>,\n\t\tpublic readonly value: InternalTypes.ValueRequiredState<T>,\n\t\tcontrolSettings: LatestValueControls,\n\t) {\n\t\tthis.controls = new LatestValueControl(controlSettings);\n\t}\n\n\tpublic get local(): InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>> {\n\t\treturn this.value.value;\n\t}\n\n\tpublic set local(value: JsonSerializable<T> & JsonDeserialized<T>) {\n\t\tthis.value.rev += 1;\n\t\tthis.value.timestamp = Date.now();\n\t\tthis.value.value = value;\n\t\tthis.datastore.localUpdate(this.key, this.value, /* forceUpdate */ false);\n\t}\n\n\tpublic *clientValues(): IterableIterator<LatestValueClientData<T>> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tfor (const [clientSessionId, value] of brandedObjectEntries(allKnownStates.states)) {\n\t\t\tif (clientSessionId !== allKnownStates.self) {\n\t\t\t\tyield {\n\t\t\t\t\tclient: this.datastore.lookupClient(clientSessionId),\n\t\t\t\t\tvalue: value.value,\n\t\t\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t\t\t};\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 Object.keys(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): LatestValueData<T> {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tif (clientSessionId in allKnownStates.states) {\n\t\t\tconst { value, rev: revision } = allKnownStates.states[clientSessionId];\n\t\t\treturn { value, metadata: { revision, timestamp: Date.now() } };\n\t\t}\n\t\tthrow new Error(\"No entry for clientId\");\n\t}\n\n\tpublic update(\n\t\tclient: ISessionClient,\n\t\t_received: number,\n\t\tvalue: InternalTypes.ValueRequiredState<T>,\n\t): void {\n\t\tconst allKnownStates = this.datastore.knownValues(this.key);\n\t\tconst clientSessionId = client.sessionId;\n\t\tif (clientSessionId in allKnownStates.states) {\n\t\t\tconst currentState = allKnownStates.states[clientSessionId];\n\t\t\tif (currentState.rev >= value.rev) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.datastore.update(this.key, clientSessionId, value);\n\t\tthis.events.emit(\"updated\", {\n\t\t\tclient,\n\t\t\tvalue: value.value,\n\t\t\tmetadata: { revision: value.rev, timestamp: value.timestamp },\n\t\t});\n\t}\n}\n\n/**\n * Factory for creating a {@link LatestValueManager}.\n *\n * @alpha\n */\nexport function Latest<T extends object, Key extends string = string>(\n\tinitialValue: JsonSerializable<T> & JsonDeserialized<T> & object,\n\tcontrols?: LatestValueControls,\n): InternalTypes.ManagerFactory<\n\tKey,\n\tInternalTypes.ValueRequiredState<T>,\n\tLatestValueManager<T>\n> {\n\t// LatestValueManager takes ownership of initialValue but makes a shallow\n\t// copy for basic protection.\n\tconst value: InternalTypes.ValueRequiredState<T> = {\n\t\trev: 0,\n\t\ttimestamp: Date.now(),\n\t\tvalue: { ...initialValue },\n\t};\n\tconst controlSettings = controls\n\t\t? { ...controls }\n\t\t: {\n\t\t\t\tallowableUpdateLatency: 60,\n\t\t\t\tforcedRefreshInterval: 0,\n\t\t\t};\n\tconst factory = (\n\t\tkey: Key,\n\t\tdatastoreHandle: InternalTypes.StateDatastoreHandle<\n\t\t\tKey,\n\t\t\tInternalTypes.ValueRequiredState<T>\n\t\t>,\n\t): {\n\t\tvalue: typeof value;\n\t\tmanager: InternalTypes.StateValue<LatestValueManager<T>>;\n\t} => ({\n\t\tvalue,\n\t\tmanager: brandIVM<LatestValueManagerImpl<T, Key>, T, InternalTypes.ValueRequiredState<T>>(\n\t\t\tnew LatestValueManagerImpl(\n\t\t\t\tkey,\n\t\t\t\tdatastoreFromHandle(datastoreHandle),\n\t\t\t\tvalue,\n\t\t\t\tcontrolSettings,\n\t\t\t),\n\t\t),\n\t});\n\treturn Object.assign(factory, { instanceBase: LatestValueManagerImpl });\n}\n"]}
@@ -0,0 +1,44 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import type { ISessionClient } from "./presence.js";
6
+ import type { JsonDeserialized } from "@fluidframework/presence/internal/core-interfaces";
7
+ import type { InternalUtilityTypes } from "@fluidframework/presence/internal/exposedUtilityTypes";
8
+ /**
9
+ * Metadata for the value state.
10
+ *
11
+ * @sealed
12
+ * @alpha
13
+ */
14
+ export interface LatestValueMetadata {
15
+ /**
16
+ * The revision number for value that increases as value is changed.
17
+ */
18
+ revision: number;
19
+ /**
20
+ * Local time when the value was last updated.
21
+ * @remarks Currently this is a placeholder for future implementation.
22
+ */
23
+ timestamp: number;
24
+ }
25
+ /**
26
+ * State of a value and its metadata.
27
+ *
28
+ * @sealed
29
+ * @alpha
30
+ */
31
+ export interface LatestValueData<T> {
32
+ value: InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;
33
+ metadata: LatestValueMetadata;
34
+ }
35
+ /**
36
+ * State of a specific client's value and its metadata.
37
+ *
38
+ * @sealed
39
+ * @alpha
40
+ */
41
+ export interface LatestValueClientData<T> extends LatestValueData<T> {
42
+ client: ISessionClient;
43
+ }
44
+ //# sourceMappingURL=latestValueTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestValueTypes.d.ts","sourceRoot":"","sources":["../src/latestValueTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mDAAmD,CAAC;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAElG;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IACjC,KAAK,EAAE,oBAAoB,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,QAAQ,EAAE,mBAAmB,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IACnE,MAAM,EAAE,cAAc,CAAC;CACvB"}
@@ -0,0 +1,6 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=latestValueTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latestValueTypes.js","sourceRoot":"","sources":["../src/latestValueTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ISessionClient } from \"./presence.js\";\n\nimport type { JsonDeserialized } from \"@fluidframework/presence/internal/core-interfaces\";\nimport type { InternalUtilityTypes } from \"@fluidframework/presence/internal/exposedUtilityTypes\";\n\n/**\n * Metadata for the value state.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueMetadata {\n\t/**\n\t * The revision number for value that increases as value is changed.\n\t */\n\trevision: number;\n\t/**\n\t * Local time when the value was last updated.\n\t * @remarks Currently this is a placeholder for future implementation.\n\t */\n\ttimestamp: number;\n}\n\n/**\n * State of a value and its metadata.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueData<T> {\n\tvalue: InternalUtilityTypes.FullyReadonly<JsonDeserialized<T>>;\n\tmetadata: LatestValueMetadata;\n}\n\n/**\n * State of a specific client's value and its metadata.\n *\n * @sealed\n * @alpha\n */\nexport interface LatestValueClientData<T> extends LatestValueData<T> {\n\tclient: ISessionClient;\n}\n"]}