@fluid-internal/presence-runtime 2.93.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.
Files changed (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -0
  3. package/dist/package.json +4 -0
  4. package/dist/packageVersion.d.ts +9 -0
  5. package/dist/packageVersion.d.ts.map +1 -0
  6. package/dist/packageVersion.js +12 -0
  7. package/dist/packageVersion.js.map +1 -0
  8. package/dist/runtime/extension/containerPresence.d.ts +53 -0
  9. package/dist/runtime/extension/containerPresence.d.ts.map +1 -0
  10. package/dist/runtime/extension/containerPresence.js +90 -0
  11. package/dist/runtime/extension/containerPresence.js.map +1 -0
  12. package/dist/runtime/extension/index.d.ts +6 -0
  13. package/dist/runtime/extension/index.d.ts.map +1 -0
  14. package/dist/runtime/extension/index.js +11 -0
  15. package/dist/runtime/extension/index.js.map +1 -0
  16. package/dist/runtime/presenceDatastoreManager.d.ts +146 -0
  17. package/dist/runtime/presenceDatastoreManager.d.ts.map +1 -0
  18. package/dist/runtime/presenceDatastoreManager.js +666 -0
  19. package/dist/runtime/presenceDatastoreManager.js.map +1 -0
  20. package/dist/runtime/presenceManager.d.ts +16 -0
  21. package/dist/runtime/presenceManager.d.ts.map +1 -0
  22. package/dist/runtime/presenceManager.js +140 -0
  23. package/dist/runtime/presenceManager.js.map +1 -0
  24. package/dist/runtime/protocol.d.ts +126 -0
  25. package/dist/runtime/protocol.d.ts.map +1 -0
  26. package/dist/runtime/protocol.js +20 -0
  27. package/dist/runtime/protocol.js.map +1 -0
  28. package/dist/runtime/runtimeTypes.d.ts +26 -0
  29. package/dist/runtime/runtimeTypes.d.ts.map +1 -0
  30. package/dist/runtime/runtimeTypes.js +7 -0
  31. package/dist/runtime/runtimeTypes.js.map +1 -0
  32. package/dist/runtime/systemWorkspace.d.ts +39 -0
  33. package/dist/runtime/systemWorkspace.d.ts.map +1 -0
  34. package/dist/runtime/systemWorkspace.js +264 -0
  35. package/dist/runtime/systemWorkspace.js.map +1 -0
  36. package/dist/runtime/test/presenceDatastoreManager.spec.js +618 -0
  37. package/dist/runtime/test/presenceDatastoreManager.spec.js.map +1 -0
  38. package/dist/runtime/test/presenceManager.spec.js +651 -0
  39. package/dist/runtime/test/presenceManager.spec.js.map +1 -0
  40. package/dist/runtime/test.d.ts +12 -0
  41. package/dist/runtime/test.d.ts.map +1 -0
  42. package/dist/runtime/test.js +15 -0
  43. package/dist/runtime/test.js.map +1 -0
  44. package/dist/states/index.d.ts +7 -0
  45. package/dist/states/index.d.ts.map +1 -0
  46. package/dist/states/index.js +12 -0
  47. package/dist/states/index.js.map +1 -0
  48. package/dist/states/latestMapValueManager.d.ts +10 -0
  49. package/dist/states/latestMapValueManager.d.ts.map +1 -0
  50. package/dist/states/latestMapValueManager.js +248 -0
  51. package/dist/states/latestMapValueManager.js.map +1 -0
  52. package/dist/states/latestValueManager.d.ts +10 -0
  53. package/dist/states/latestValueManager.d.ts.map +1 -0
  54. package/dist/states/latestValueManager.js +115 -0
  55. package/dist/states/latestValueManager.js.map +1 -0
  56. package/dist/states/notificationsManager.d.ts +26 -0
  57. package/dist/states/notificationsManager.d.ts.map +1 -0
  58. package/dist/states/notificationsManager.js +97 -0
  59. package/dist/states/notificationsManager.js.map +1 -0
  60. package/dist/states/presence.d.ts +11 -0
  61. package/dist/states/presence.d.ts.map +1 -0
  62. package/dist/states/presence.js +7 -0
  63. package/dist/states/presence.js.map +1 -0
  64. package/dist/states/stateFactory.d.ts +18 -0
  65. package/dist/states/stateFactory.d.ts.map +1 -0
  66. package/dist/states/stateFactory.js +23 -0
  67. package/dist/states/stateFactory.js.map +1 -0
  68. package/dist/states/test/batching.spec.js +843 -0
  69. package/dist/states/test/batching.spec.js.map +1 -0
  70. package/dist/states/test/broadcastControlsTests.js +60 -0
  71. package/dist/states/test/broadcastControlsTests.js.map +1 -0
  72. package/dist/states/test/eventing.spec.js +576 -0
  73. package/dist/states/test/eventing.spec.js.map +1 -0
  74. package/dist/states/test/latestMapValueManager.spec.js +210 -0
  75. package/dist/states/test/latestMapValueManager.spec.js.map +1 -0
  76. package/dist/states/test/latestValueManager.spec.js +193 -0
  77. package/dist/states/test/latestValueManager.spec.js.map +1 -0
  78. package/dist/states/test/mockEphemeralRuntime.js +11 -0
  79. package/dist/states/test/mockEphemeralRuntime.js.map +1 -0
  80. package/dist/states/test/notificationsManager.spec.js +460 -0
  81. package/dist/states/test/notificationsManager.spec.js.map +1 -0
  82. package/dist/states/test/presenceStates.spec.js +73 -0
  83. package/dist/states/test/presenceStates.spec.js.map +1 -0
  84. package/dist/states/test/schemaValidation/protocol.spec.js +246 -0
  85. package/dist/states/test/schemaValidation/protocol.spec.js.map +1 -0
  86. package/dist/states/test/schemaValidation/valueManagers.spec.js +784 -0
  87. package/dist/states/test/schemaValidation/valueManagers.spec.js.map +1 -0
  88. package/dist/states/test/testUtils.js +21 -0
  89. package/dist/states/test/testUtils.js.map +1 -0
  90. package/dist/states/validatedGetter.d.ts +18 -0
  91. package/dist/states/validatedGetter.d.ts.map +1 -0
  92. package/dist/states/validatedGetter.js +43 -0
  93. package/dist/states/validatedGetter.js.map +1 -0
  94. package/dist/test/mockEphemeralRuntime.js +175 -0
  95. package/dist/test/mockEphemeralRuntime.js.map +1 -0
  96. package/dist/test/testUtils.js +262 -0
  97. package/dist/test/testUtils.js.map +1 -0
  98. package/dist/test/utils/index.js +27 -0
  99. package/dist/test/utils/index.js.map +1 -0
  100. package/dist/utils/broadcastControls.d.ts +37 -0
  101. package/dist/utils/broadcastControls.d.ts.map +1 -0
  102. package/dist/utils/broadcastControls.js +60 -0
  103. package/dist/utils/broadcastControls.js.map +1 -0
  104. package/dist/utils/index.d.ts +9 -0
  105. package/dist/utils/index.d.ts.map +1 -0
  106. package/dist/utils/index.js +26 -0
  107. package/dist/utils/index.js.map +1 -0
  108. package/dist/utils/internalUtils.d.ts +125 -0
  109. package/dist/utils/internalUtils.d.ts.map +1 -0
  110. package/dist/utils/internalUtils.js +99 -0
  111. package/dist/utils/internalUtils.js.map +1 -0
  112. package/dist/utils/test/timerManager.spec.js +93 -0
  113. package/dist/utils/test/timerManager.spec.js.map +1 -0
  114. package/dist/utils/timerManager.d.ts +37 -0
  115. package/dist/utils/timerManager.d.ts.map +1 -0
  116. package/dist/utils/timerManager.js +65 -0
  117. package/dist/utils/timerManager.js.map +1 -0
  118. package/dist/utils/valueManager.d.ts +14 -0
  119. package/dist/utils/valueManager.d.ts.map +1 -0
  120. package/dist/utils/valueManager.js +22 -0
  121. package/dist/utils/valueManager.js.map +1 -0
  122. package/dist/workspace/index.d.ts +7 -0
  123. package/dist/workspace/index.d.ts.map +1 -0
  124. package/dist/workspace/index.js +14 -0
  125. package/dist/workspace/index.js.map +1 -0
  126. package/dist/workspace/presenceStates.d.ts +61 -0
  127. package/dist/workspace/presenceStates.d.ts.map +1 -0
  128. package/dist/workspace/presenceStates.js +235 -0
  129. package/dist/workspace/presenceStates.js.map +1 -0
  130. package/dist/workspace/stateDatastore.d.ts +17 -0
  131. package/dist/workspace/stateDatastore.d.ts.map +1 -0
  132. package/dist/workspace/stateDatastore.js +24 -0
  133. package/dist/workspace/stateDatastore.js.map +1 -0
  134. package/lib/packageVersion.d.ts +9 -0
  135. package/lib/packageVersion.d.ts.map +1 -0
  136. package/lib/packageVersion.js +9 -0
  137. package/lib/packageVersion.js.map +1 -0
  138. package/lib/runtime/extension/containerPresence.d.ts +53 -0
  139. package/lib/runtime/extension/containerPresence.d.ts.map +1 -0
  140. package/lib/runtime/extension/containerPresence.js +87 -0
  141. package/lib/runtime/extension/containerPresence.js.map +1 -0
  142. package/lib/runtime/extension/index.d.ts +6 -0
  143. package/lib/runtime/extension/index.d.ts.map +1 -0
  144. package/lib/runtime/extension/index.js +6 -0
  145. package/lib/runtime/extension/index.js.map +1 -0
  146. package/lib/runtime/presenceDatastoreManager.d.ts +146 -0
  147. package/lib/runtime/presenceDatastoreManager.d.ts.map +1 -0
  148. package/lib/runtime/presenceDatastoreManager.js +662 -0
  149. package/lib/runtime/presenceDatastoreManager.js.map +1 -0
  150. package/lib/runtime/presenceManager.d.ts +16 -0
  151. package/lib/runtime/presenceManager.d.ts.map +1 -0
  152. package/lib/runtime/presenceManager.js +136 -0
  153. package/lib/runtime/presenceManager.js.map +1 -0
  154. package/lib/runtime/protocol.d.ts +126 -0
  155. package/lib/runtime/protocol.d.ts.map +1 -0
  156. package/lib/runtime/protocol.js +17 -0
  157. package/lib/runtime/protocol.js.map +1 -0
  158. package/lib/runtime/runtimeTypes.d.ts +26 -0
  159. package/lib/runtime/runtimeTypes.d.ts.map +1 -0
  160. package/lib/runtime/runtimeTypes.js +6 -0
  161. package/lib/runtime/runtimeTypes.js.map +1 -0
  162. package/lib/runtime/systemWorkspace.d.ts +39 -0
  163. package/lib/runtime/systemWorkspace.d.ts.map +1 -0
  164. package/lib/runtime/systemWorkspace.js +260 -0
  165. package/lib/runtime/systemWorkspace.js.map +1 -0
  166. package/lib/runtime/test/presenceDatastoreManager.spec.js +616 -0
  167. package/lib/runtime/test/presenceDatastoreManager.spec.js.map +1 -0
  168. package/lib/runtime/test/presenceManager.spec.js +649 -0
  169. package/lib/runtime/test/presenceManager.spec.js.map +1 -0
  170. package/lib/runtime/test.d.ts +12 -0
  171. package/lib/runtime/test.d.ts.map +1 -0
  172. package/lib/runtime/test.js +10 -0
  173. package/lib/runtime/test.js.map +1 -0
  174. package/lib/states/index.d.ts +7 -0
  175. package/lib/states/index.d.ts.map +1 -0
  176. package/lib/states/index.js +7 -0
  177. package/lib/states/index.js.map +1 -0
  178. package/lib/states/latestMapValueManager.d.ts +10 -0
  179. package/lib/states/latestMapValueManager.d.ts.map +1 -0
  180. package/lib/states/latestMapValueManager.js +244 -0
  181. package/lib/states/latestMapValueManager.js.map +1 -0
  182. package/lib/states/latestValueManager.d.ts +10 -0
  183. package/lib/states/latestValueManager.d.ts.map +1 -0
  184. package/lib/states/latestValueManager.js +111 -0
  185. package/lib/states/latestValueManager.js.map +1 -0
  186. package/lib/states/notificationsManager.d.ts +26 -0
  187. package/lib/states/notificationsManager.d.ts.map +1 -0
  188. package/lib/states/notificationsManager.js +93 -0
  189. package/lib/states/notificationsManager.js.map +1 -0
  190. package/lib/states/presence.d.ts +11 -0
  191. package/lib/states/presence.d.ts.map +1 -0
  192. package/lib/states/presence.js +6 -0
  193. package/lib/states/presence.js.map +1 -0
  194. package/lib/states/stateFactory.d.ts +18 -0
  195. package/lib/states/stateFactory.d.ts.map +1 -0
  196. package/lib/states/stateFactory.js +20 -0
  197. package/lib/states/stateFactory.js.map +1 -0
  198. package/lib/states/test/batching.spec.js +841 -0
  199. package/lib/states/test/batching.spec.js.map +1 -0
  200. package/lib/states/test/broadcastControlsTests.js +56 -0
  201. package/lib/states/test/broadcastControlsTests.js.map +1 -0
  202. package/lib/states/test/eventing.spec.js +574 -0
  203. package/lib/states/test/eventing.spec.js.map +1 -0
  204. package/lib/states/test/latestMapValueManager.spec.js +206 -0
  205. package/lib/states/test/latestMapValueManager.spec.js.map +1 -0
  206. package/lib/states/test/latestValueManager.spec.js +189 -0
  207. package/lib/states/test/latestValueManager.spec.js.map +1 -0
  208. package/lib/states/test/mockEphemeralRuntime.js +6 -0
  209. package/lib/states/test/mockEphemeralRuntime.js.map +1 -0
  210. package/lib/states/test/notificationsManager.spec.js +456 -0
  211. package/lib/states/test/notificationsManager.spec.js.map +1 -0
  212. package/lib/states/test/presenceStates.spec.js +69 -0
  213. package/lib/states/test/presenceStates.spec.js.map +1 -0
  214. package/lib/states/test/schemaValidation/protocol.spec.js +244 -0
  215. package/lib/states/test/schemaValidation/protocol.spec.js.map +1 -0
  216. package/lib/states/test/schemaValidation/valueManagers.spec.js +782 -0
  217. package/lib/states/test/schemaValidation/valueManagers.spec.js.map +1 -0
  218. package/lib/states/test/testUtils.js +6 -0
  219. package/lib/states/test/testUtils.js.map +1 -0
  220. package/lib/states/validatedGetter.d.ts +18 -0
  221. package/lib/states/validatedGetter.d.ts.map +1 -0
  222. package/lib/states/validatedGetter.js +39 -0
  223. package/lib/states/validatedGetter.js.map +1 -0
  224. package/lib/test/mockEphemeralRuntime.js +171 -0
  225. package/lib/test/mockEphemeralRuntime.js.map +1 -0
  226. package/lib/test/testUtils.js +251 -0
  227. package/lib/test/testUtils.js.map +1 -0
  228. package/lib/test/utils/index.js +8 -0
  229. package/lib/test/utils/index.js.map +1 -0
  230. package/lib/utils/broadcastControls.d.ts +37 -0
  231. package/lib/utils/broadcastControls.d.ts.map +1 -0
  232. package/lib/utils/broadcastControls.js +55 -0
  233. package/lib/utils/broadcastControls.js.map +1 -0
  234. package/lib/utils/index.d.ts +9 -0
  235. package/lib/utils/index.d.ts.map +1 -0
  236. package/lib/utils/index.js +9 -0
  237. package/lib/utils/index.js.map +1 -0
  238. package/lib/utils/internalUtils.d.ts +125 -0
  239. package/lib/utils/internalUtils.d.ts.map +1 -0
  240. package/lib/utils/internalUtils.js +90 -0
  241. package/lib/utils/internalUtils.js.map +1 -0
  242. package/lib/utils/test/timerManager.spec.js +91 -0
  243. package/lib/utils/test/timerManager.spec.js.map +1 -0
  244. package/lib/utils/timerManager.d.ts +37 -0
  245. package/lib/utils/timerManager.d.ts.map +1 -0
  246. package/lib/utils/timerManager.js +61 -0
  247. package/lib/utils/timerManager.js.map +1 -0
  248. package/lib/utils/valueManager.d.ts +14 -0
  249. package/lib/utils/valueManager.d.ts.map +1 -0
  250. package/lib/utils/valueManager.js +17 -0
  251. package/lib/utils/valueManager.js.map +1 -0
  252. package/lib/workspace/index.d.ts +7 -0
  253. package/lib/workspace/index.d.ts.map +1 -0
  254. package/lib/workspace/index.js +7 -0
  255. package/lib/workspace/index.js.map +1 -0
  256. package/lib/workspace/presenceStates.d.ts +61 -0
  257. package/lib/workspace/presenceStates.d.ts.map +1 -0
  258. package/lib/workspace/presenceStates.js +229 -0
  259. package/lib/workspace/presenceStates.js.map +1 -0
  260. package/lib/workspace/stateDatastore.d.ts +17 -0
  261. package/lib/workspace/stateDatastore.d.ts.map +1 -0
  262. package/lib/workspace/stateDatastore.js +19 -0
  263. package/lib/workspace/stateDatastore.js.map +1 -0
  264. package/package.json +158 -0
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createSpiedValidator = exports.assertFinalExpectations = exports.prepareDisconnectedPresence = exports.prepareConnectedPresence = exports.generateBasicClientJoin = exports.localAttendeeId = exports.connectionId1 = exports.attendeeId1 = exports.createSpecificAttendeeId = exports.createInstanceOf = exports.assertIdenticalTypes = void 0;
8
+ const internal_1 = require("@fluidframework/test-utils/internal");
9
+ const sinon_1 = require("sinon");
10
+ const test_1 = require("@fluid-internal/presence-runtime/internal/test");
11
+ const mockEphemeralRuntime_js_1 = require("./mockEphemeralRuntime.js");
12
+ /**
13
+ * Use to compile-time assert types of two variables are identical.
14
+ */
15
+ function assertIdenticalTypes(_actual, _expected) {
16
+ return undefined;
17
+ }
18
+ exports.assertIdenticalTypes = assertIdenticalTypes;
19
+ /**
20
+ * Creates a non-viable (`undefined`) instance of type T to be used for type checking.
21
+ */
22
+ function createInstanceOf() {
23
+ return undefined;
24
+ }
25
+ exports.createInstanceOf = createInstanceOf;
26
+ /**
27
+ * Forms {@link AttendeeId} for a specific attendee
28
+ */
29
+ function createSpecificAttendeeId(id) {
30
+ return id;
31
+ }
32
+ exports.createSpecificAttendeeId = createSpecificAttendeeId;
33
+ /**
34
+ * Mock {@link AttendeeId}.
35
+ */
36
+ exports.attendeeId1 = createSpecificAttendeeId("attendeeId-1");
37
+ /**
38
+ * Mock {@link ClientConnectionId}.
39
+ */
40
+ exports.connectionId1 = "client1";
41
+ /**
42
+ * Mock {@link AttendeeId} for the local client in tests.
43
+ */
44
+ exports.localAttendeeId = createSpecificAttendeeId("localAttendeeId");
45
+ /**
46
+ * Generates expected inbound join signal for a client that was initialized while connected.
47
+ */
48
+ function generateBasicClientJoin(fixedTime, { attendeeId = exports.localAttendeeId, clientConnectionId = mockEphemeralRuntime_js_1.initialLocalClientConnectionId, updateProviders = ["client0", "client1", "client3"], connectionOrder = 0, averageLatency = 0, priorClientToSessionId = {}, }) {
49
+ return {
50
+ type: "Pres:ClientJoin",
51
+ content: {
52
+ "avgLatency": averageLatency,
53
+ "data": {
54
+ "system:presence": {
55
+ "clientToSessionId": {
56
+ ...priorClientToSessionId,
57
+ [clientConnectionId]: {
58
+ "rev": connectionOrder,
59
+ "timestamp": fixedTime,
60
+ "value": attendeeId,
61
+ },
62
+ },
63
+ },
64
+ },
65
+ "sendTimestamp": fixedTime,
66
+ updateProviders,
67
+ },
68
+ clientId: clientConnectionId,
69
+ };
70
+ }
71
+ exports.generateBasicClientJoin = generateBasicClientJoin;
72
+ /**
73
+ * Creates a processSignal wrapper function for a presence manager.
74
+ */
75
+ function createProcessSignal(presence) {
76
+ return (addressChain, signalMessage, local) => {
77
+ // Pass on to presence manager, but first clone the message to avoid
78
+ // possibility of Presence mutating the original message which often
79
+ // contains reference to general (shared) test data.
80
+ // Additionally JSON.parse(JSON.stringify(signalMessage)) is used to
81
+ // ensure only regular JSON-serializable data is passed to Presence.
82
+ // In production environment, the message is always extracted from
83
+ // the network and Presence can safely mutate it.
84
+ presence.processSignal(addressChain,
85
+ // eslint-disable-next-line unicorn/prefer-structured-clone -- not structural clone, but filters to JSON-serializable data
86
+ JSON.parse(JSON.stringify(signalMessage)), local);
87
+ };
88
+ }
89
+ /**
90
+ * Calculates update providers based on current audience members.
91
+ */
92
+ function calculateUpdateProviders(runtime, clientConnectionId) {
93
+ // This logic needs to be kept in sync with datastore manager.
94
+ // From PresenceDatastoreManager.getAudienceInformation:
95
+ const members = runtime.audience.getMembers();
96
+ members.delete(clientConnectionId);
97
+ const all = new Set();
98
+ const writers = new Set();
99
+ for (const [id, client] of members) {
100
+ if (client.details.capabilities.interactive) {
101
+ all.add(id);
102
+ if (client.mode === "write") {
103
+ writers.add(id);
104
+ }
105
+ }
106
+ }
107
+ // From PresenceDatastoreManager.joinSession:
108
+ const updateProviders = [...(writers.size > 0 ? writers : all)];
109
+ if (updateProviders.length > 3) {
110
+ updateProviders.length = 3;
111
+ }
112
+ return updateProviders;
113
+ }
114
+ /**
115
+ * Prepares the expected client join signal and calculates update providers.
116
+ */
117
+ function prepareExpectedClientJoin(runtime, attendeeId, clientConnectionId, clock) {
118
+ const updateProviders = calculateUpdateProviders(runtime, clientConnectionId);
119
+ const expectedClientJoin = generateBasicClientJoin(clock.now, {
120
+ attendeeId,
121
+ clientConnectionId,
122
+ updateProviders,
123
+ });
124
+ delete expectedClientJoin.clientId;
125
+ runtime.signalsExpected.push([expectedClientJoin]);
126
+ return { expectedClientJoin, updateProviders };
127
+ }
128
+ /**
129
+ * Processes the local join signal and sends a fake join response.
130
+ */
131
+ function processJoinSignalAndResponse(processSignal, expectedClientJoin, clientConnectionId, updateProviders, clock, latency) {
132
+ // Pass a little time (to mimic reality)
133
+ clock.tick(latency);
134
+ // Return the [local] join signal
135
+ processSignal([], { ...expectedClientJoin, clientId: clientConnectionId }, true);
136
+ if (updateProviders.length > 0) {
137
+ // Pass time (to mimic likely response)
138
+ clock.tick(test_1.broadcastJoinResponseDelaysMs.namedResponder + 20);
139
+ // Send a fake join response
140
+ // There are no other attendees in the session (not realistic) but this
141
+ // convinces the presence manager that it now has full knowledge, which
142
+ // enables it to respond to other's join requests accurately.
143
+ processSignal([], {
144
+ type: "Pres:DatastoreUpdate",
145
+ content: {
146
+ ...expectedClientJoin.content,
147
+ isComplete: true,
148
+ joinResponseFor: [clientConnectionId],
149
+ },
150
+ clientId: updateProviders[0],
151
+ }, false);
152
+ }
153
+ }
154
+ /**
155
+ * The simulated local average latency used in test helpers.
156
+ */
157
+ const localAvgLatency = 10;
158
+ /**
159
+ * Creates presence manager for testing.
160
+ */
161
+ function createPresence(runtime, attendeeId, logger) {
162
+ logger.registerExpectedEvent({ eventName: "Presence:PresenceInstantiated" });
163
+ const presence = (0, test_1.createPresenceManager)(runtime, attendeeId);
164
+ const processSignal = createProcessSignal(presence);
165
+ // Validate expectations post initialization to make sure logger
166
+ // and runtime are left in a clean expectation state.
167
+ const logErrors = (0, internal_1.getUnexpectedLogErrorException)(logger);
168
+ if (logErrors) {
169
+ throw logErrors;
170
+ }
171
+ return { presence, processSignal };
172
+ }
173
+ /**
174
+ * Prepares an instance of presence as it would be if initialized while connected.
175
+ *
176
+ * @param runtime - the mock runtime
177
+ * @param attendeeId - the client session id given to presence
178
+ * @param clientConnectionId - the client connection id
179
+ * @param clock - the fake timer.
180
+ * @param logger - logger to track telemetry events
181
+ */
182
+ function prepareConnectedPresence(runtime, attendeeId, clientConnectionId, clock, logger) {
183
+ // Set runtime to connected state
184
+ runtime.clientId = clientConnectionId;
185
+ runtime.joined = true;
186
+ const { expectedClientJoin, updateProviders } = prepareExpectedClientJoin(runtime, attendeeId, clientConnectionId, clock);
187
+ const { presence, processSignal } = createPresence(runtime, attendeeId, logger);
188
+ runtime.assertAllSignalsSubmitted();
189
+ processJoinSignalAndResponse(processSignal, expectedClientJoin, clientConnectionId, updateProviders, clock, localAvgLatency);
190
+ return {
191
+ presence,
192
+ processSignal,
193
+ localAvgLatency,
194
+ };
195
+ }
196
+ exports.prepareConnectedPresence = prepareConnectedPresence;
197
+ /**
198
+ * Prepares an instance of presence in a disconnected state.
199
+ *
200
+ * @remarks
201
+ * Use this helper when you need to test events that occur during the initial
202
+ * connection, such as `attendeeConnected` for the local client.
203
+ *
204
+ * @param runtime - the mock runtime
205
+ * @param attendeeId - the client session id given to presence
206
+ * @param clientConnectionId - the client connection id to use when connecting
207
+ * @param clock - the fake timer
208
+ * @param logger - logger to track telemetry events
209
+ */
210
+ function prepareDisconnectedPresence(runtime, attendeeId, clientConnectionId, clock, logger) {
211
+ // Ensure runtime is in disconnected state
212
+ runtime.clientId = undefined;
213
+ runtime.joined = false;
214
+ // Remove client connection id from audience if present
215
+ if (runtime.audience.getMember(clientConnectionId) !== undefined) {
216
+ runtime.removeMember(clientConnectionId);
217
+ }
218
+ const { presence, processSignal } = createPresence(runtime, attendeeId, logger);
219
+ const connect = () => {
220
+ const { expectedClientJoin, updateProviders } = prepareExpectedClientJoin(runtime, attendeeId, clientConnectionId, clock);
221
+ // Simulate connection
222
+ runtime.connect(clientConnectionId, undefined);
223
+ // Validate signal was submitted
224
+ runtime.assertAllSignalsSubmitted();
225
+ processJoinSignalAndResponse(processSignal, expectedClientJoin, clientConnectionId, updateProviders, clock, localAvgLatency);
226
+ };
227
+ return {
228
+ presence,
229
+ processSignal,
230
+ connect,
231
+ localAvgLatency,
232
+ };
233
+ }
234
+ exports.prepareDisconnectedPresence = prepareDisconnectedPresence;
235
+ /**
236
+ * Asserts that all expected telemetry and signals were sent.
237
+ */
238
+ function assertFinalExpectations(runtime, logger) {
239
+ // Make sure all expected events were logged and there are no unexpected errors.
240
+ const logErrors = (0, internal_1.getUnexpectedLogErrorException)(logger);
241
+ if (logErrors) {
242
+ throw logErrors;
243
+ }
244
+ // Make sure all expected signals were sent.
245
+ runtime.assertAllSignalsSubmitted();
246
+ }
247
+ exports.assertFinalExpectations = assertFinalExpectations;
248
+ /**
249
+ * A null validator (one that does nothing) for a given type T. It simply casts the value to
250
+ * `JsonDeserialized<T>`.
251
+ */
252
+ const nullValidator = (data) => {
253
+ return data;
254
+ };
255
+ /**
256
+ * Creates a spied validator for test purposes.
257
+ *
258
+ * @param validatorFunction - A {@link StateSchemaValidator} to wrap in a spy.
259
+ */
260
+ const createSpiedValidator = (validatorFunction = (nullValidator)) => (0, sinon_1.spy)(validatorFunction);
261
+ exports.createSpiedValidator = createSpiedValidator;
262
+ //# sourceMappingURL=testUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../../src/test/testUtils.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 {\n\tAttendeeId,\n\tClientConnectionId,\n\tPresenceWithNotifications,\n\tStateSchemaValidator,\n} from \"@fluid-internal/presence-definitions\";\nimport type { InboundExtensionMessage } from \"@fluidframework/container-runtime-definitions/internal\";\nimport type {\n\tInternalCoreInterfacesUtilityTypes,\n\tJsonDeserialized,\n} from \"@fluidframework/core-interfaces/internal\";\nimport type { EventAndErrorTrackingLogger } from \"@fluidframework/test-utils/internal\";\nimport { getUnexpectedLogErrorException } from \"@fluidframework/test-utils/internal\";\nimport { spy } from \"sinon\";\nimport type { SinonFakeTimers } from \"sinon\";\n\nimport type {\n\tInboundClientJoinMessage,\n\tInboundDatastoreUpdateMessage,\n\tOutboundClientJoinMessage,\n\tSignalMessages,\n\tSystemWorkspaceDatastore,\n} from \"@fluid-internal/presence-runtime/internal/protocol\";\nimport {\n\tbroadcastJoinResponseDelaysMs,\n\tcreatePresenceManager,\n} from \"@fluid-internal/presence-runtime/internal/test\";\n\nimport type { MockEphemeralRuntime } from \"./mockEphemeralRuntime.js\";\nimport { initialLocalClientConnectionId } from \"./mockEphemeralRuntime.js\";\n\n/**\n * Use to compile-time assert types of two variables are identical.\n */\nexport function assertIdenticalTypes<T, U>(\n\t_actual: T & InternalCoreInterfacesUtilityTypes.IfSameType<T, U>,\n\t_expected: U & InternalCoreInterfacesUtilityTypes.IfSameType<T, U>,\n): InternalCoreInterfacesUtilityTypes.IfSameType<T, U> {\n\treturn undefined as InternalCoreInterfacesUtilityTypes.IfSameType<T, U>;\n}\n\n/**\n * Creates a non-viable (`undefined`) instance of type T to be used for type checking.\n */\nexport function createInstanceOf<T>(): T {\n\treturn undefined as T;\n}\n\ntype SpecificAttendeeId<T extends string> = string extends T\n\t? never\n\t: Exclude<T & AttendeeId, never>;\n\n/**\n * Forms {@link AttendeeId} for a specific attendee\n */\nexport function createSpecificAttendeeId<const T extends string>(\n\tid: T,\n): SpecificAttendeeId<T> {\n\treturn id as SpecificAttendeeId<T>;\n}\n\n/**\n * Mock {@link AttendeeId}.\n */\nexport const attendeeId1 = createSpecificAttendeeId(\"attendeeId-1\");\n/**\n * Mock {@link ClientConnectionId}.\n */\nexport const connectionId1 = \"client1\" as const satisfies ClientConnectionId;\n/**\n * Mock {@link AttendeeId} for the local client in tests.\n */\nexport const localAttendeeId = createSpecificAttendeeId(\"localAttendeeId\");\n\n/**\n * Generates expected inbound join signal for a client that was initialized while connected.\n */\nexport function generateBasicClientJoin(\n\tfixedTime: number,\n\t{\n\t\tattendeeId = localAttendeeId,\n\t\tclientConnectionId = initialLocalClientConnectionId,\n\t\tupdateProviders = [\"client0\", \"client1\", \"client3\"],\n\t\tconnectionOrder = 0,\n\t\taverageLatency = 0,\n\t\tpriorClientToSessionId = {},\n\t}: {\n\t\tattendeeId?: string;\n\t\tclientConnectionId?: ClientConnectionId;\n\t\tupdateProviders?: string[];\n\t\tconnectionOrder?: number;\n\t\taverageLatency?: number;\n\t\tpriorClientToSessionId?: SystemWorkspaceDatastore[\"clientToSessionId\"];\n\t},\n): InboundClientJoinMessage {\n\treturn {\n\t\ttype: \"Pres:ClientJoin\",\n\t\tcontent: {\n\t\t\t\"avgLatency\": averageLatency,\n\t\t\t\"data\": {\n\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t...priorClientToSessionId,\n\t\t\t\t\t\t[clientConnectionId]: {\n\t\t\t\t\t\t\t\"rev\": connectionOrder,\n\t\t\t\t\t\t\t\"timestamp\": fixedTime,\n\t\t\t\t\t\t\t\"value\": attendeeId as AttendeeId,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"sendTimestamp\": fixedTime,\n\t\t\tupdateProviders,\n\t\t},\n\t\tclientId: clientConnectionId,\n\t};\n}\n\n/**\n * Function signature for sending a signal to the presence manager.\n */\nexport type ProcessSignalFunction = ReturnType<typeof createPresenceManager>[\"processSignal\"];\n\n/**\n * Expected shape of Presence signals\n */\nexport type InboundPresenceSignalMessage = InboundExtensionMessage<SignalMessages>;\n\n/**\n * Creates a processSignal wrapper function for a presence manager.\n */\nfunction createProcessSignal(\n\tpresence: ReturnType<typeof createPresenceManager>,\n): ProcessSignalFunction {\n\treturn (\n\t\taddressChain: string[],\n\t\tsignalMessage: InboundPresenceSignalMessage,\n\t\tlocal: boolean,\n\t): void => {\n\t\t// Pass on to presence manager, but first clone the message to avoid\n\t\t// possibility of Presence mutating the original message which often\n\t\t// contains reference to general (shared) test data.\n\t\t// Additionally JSON.parse(JSON.stringify(signalMessage)) is used to\n\t\t// ensure only regular JSON-serializable data is passed to Presence.\n\t\t// In production environment, the message is always extracted from\n\t\t// the network and Presence can safely mutate it.\n\t\tpresence.processSignal(\n\t\t\taddressChain,\n\t\t\t// eslint-disable-next-line unicorn/prefer-structured-clone -- not structural clone, but filters to JSON-serializable data\n\t\t\tJSON.parse(JSON.stringify(signalMessage)) as InboundPresenceSignalMessage,\n\t\t\tlocal,\n\t\t);\n\t};\n}\n\n/**\n * Calculates update providers based on current audience members.\n */\nfunction calculateUpdateProviders(\n\truntime: MockEphemeralRuntime,\n\tclientConnectionId: ClientConnectionId,\n): ClientConnectionId[] {\n\t// This logic needs to be kept in sync with datastore manager.\n\t// From PresenceDatastoreManager.getAudienceInformation:\n\tconst members = runtime.audience.getMembers();\n\tmembers.delete(clientConnectionId);\n\tconst all = new Set<ClientConnectionId>();\n\tconst writers = new Set<ClientConnectionId>();\n\tfor (const [id, client] of members) {\n\t\tif (client.details.capabilities.interactive) {\n\t\t\tall.add(id);\n\t\t\tif (client.mode === \"write\") {\n\t\t\t\twriters.add(id);\n\t\t\t}\n\t\t}\n\t}\n\t// From PresenceDatastoreManager.joinSession:\n\tconst updateProviders = [...(writers.size > 0 ? writers : all)];\n\tif (updateProviders.length > 3) {\n\t\tupdateProviders.length = 3;\n\t}\n\treturn updateProviders;\n}\n\n/**\n * Prepares the expected client join signal and calculates update providers.\n */\nfunction prepareExpectedClientJoin(\n\truntime: MockEphemeralRuntime,\n\tattendeeId: string,\n\tclientConnectionId: ClientConnectionId,\n\tclock: Omit<SinonFakeTimers, \"restore\">,\n): {\n\texpectedClientJoin: OutboundClientJoinMessage &\n\t\tPartial<Pick<InboundClientJoinMessage, \"clientId\">>;\n\tupdateProviders: ClientConnectionId[];\n} {\n\tconst updateProviders = calculateUpdateProviders(runtime, clientConnectionId);\n\n\tconst expectedClientJoin: OutboundClientJoinMessage &\n\t\tPartial<Pick<InboundClientJoinMessage, \"clientId\">> = generateBasicClientJoin(clock.now, {\n\t\tattendeeId,\n\t\tclientConnectionId,\n\t\tupdateProviders,\n\t});\n\tdelete expectedClientJoin.clientId;\n\truntime.signalsExpected.push([expectedClientJoin]);\n\n\treturn { expectedClientJoin, updateProviders };\n}\n\n/**\n * Processes the local join signal and sends a fake join response.\n */\nfunction processJoinSignalAndResponse(\n\tprocessSignal: ProcessSignalFunction,\n\texpectedClientJoin: OutboundClientJoinMessage &\n\t\tPartial<Pick<InboundClientJoinMessage, \"clientId\">>,\n\tclientConnectionId: ClientConnectionId,\n\tupdateProviders: ClientConnectionId[],\n\tclock: Omit<SinonFakeTimers, \"restore\">,\n\tlatency: number,\n): void {\n\t// Pass a little time (to mimic reality)\n\tclock.tick(latency);\n\n\t// Return the [local] join signal\n\tprocessSignal([], { ...expectedClientJoin, clientId: clientConnectionId }, true);\n\n\tif (updateProviders.length > 0) {\n\t\t// Pass time (to mimic likely response)\n\t\tclock.tick(broadcastJoinResponseDelaysMs.namedResponder + 20);\n\n\t\t// Send a fake join response\n\t\t// There are no other attendees in the session (not realistic) but this\n\t\t// convinces the presence manager that it now has full knowledge, which\n\t\t// enables it to respond to other's join requests accurately.\n\t\tprocessSignal(\n\t\t\t[],\n\t\t\t{\n\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\tcontent: {\n\t\t\t\t\t...expectedClientJoin.content,\n\t\t\t\t\tisComplete: true,\n\t\t\t\t\tjoinResponseFor: [clientConnectionId],\n\t\t\t\t},\n\t\t\t\tclientId: updateProviders[0],\n\t\t\t} satisfies InboundDatastoreUpdateMessage,\n\t\t\tfalse,\n\t\t);\n\t}\n}\n\n/**\n * The simulated local average latency used in test helpers.\n */\nconst localAvgLatency = 10;\n\n/**\n * Creates presence manager for testing.\n */\nfunction createPresence(\n\truntime: MockEphemeralRuntime,\n\tattendeeId: string,\n\tlogger: EventAndErrorTrackingLogger,\n): {\n\tpresence: ReturnType<typeof createPresenceManager>;\n\tprocessSignal: ProcessSignalFunction;\n} {\n\tlogger.registerExpectedEvent({ eventName: \"Presence:PresenceInstantiated\" });\n\n\tconst presence = createPresenceManager(runtime, attendeeId as AttendeeId);\n\tconst processSignal = createProcessSignal(presence);\n\n\t// Validate expectations post initialization to make sure logger\n\t// and runtime are left in a clean expectation state.\n\tconst logErrors = getUnexpectedLogErrorException(logger);\n\tif (logErrors) {\n\t\tthrow logErrors;\n\t}\n\n\treturn { presence, processSignal };\n}\n\n/**\n * Prepares an instance of presence as it would be if initialized while connected.\n *\n * @param runtime - the mock runtime\n * @param attendeeId - the client session id given to presence\n * @param clientConnectionId - the client connection id\n * @param clock - the fake timer.\n * @param logger - logger to track telemetry events\n */\nexport function prepareConnectedPresence(\n\truntime: MockEphemeralRuntime,\n\tattendeeId: string,\n\tclientConnectionId: ClientConnectionId,\n\tclock: Omit<SinonFakeTimers, \"restore\">,\n\tlogger: EventAndErrorTrackingLogger,\n): {\n\tpresence: PresenceWithNotifications;\n\tprocessSignal: ProcessSignalFunction;\n\tlocalAvgLatency: number;\n} {\n\t// Set runtime to connected state\n\truntime.clientId = clientConnectionId;\n\truntime.joined = true;\n\n\tconst { expectedClientJoin, updateProviders } = prepareExpectedClientJoin(\n\t\truntime,\n\t\tattendeeId,\n\t\tclientConnectionId,\n\t\tclock,\n\t);\n\n\tconst { presence, processSignal } = createPresence(runtime, attendeeId, logger);\n\truntime.assertAllSignalsSubmitted();\n\n\tprocessJoinSignalAndResponse(\n\t\tprocessSignal,\n\t\texpectedClientJoin,\n\t\tclientConnectionId,\n\t\tupdateProviders,\n\t\tclock,\n\t\tlocalAvgLatency,\n\t);\n\n\treturn {\n\t\tpresence,\n\t\tprocessSignal,\n\t\tlocalAvgLatency,\n\t};\n}\n\n/**\n * Prepares an instance of presence in a disconnected state.\n *\n * @remarks\n * Use this helper when you need to test events that occur during the initial\n * connection, such as `attendeeConnected` for the local client.\n *\n * @param runtime - the mock runtime\n * @param attendeeId - the client session id given to presence\n * @param clientConnectionId - the client connection id to use when connecting\n * @param clock - the fake timer\n * @param logger - logger to track telemetry events\n */\nexport function prepareDisconnectedPresence(\n\truntime: MockEphemeralRuntime,\n\tattendeeId: string,\n\tclientConnectionId: ClientConnectionId,\n\tclock: Omit<SinonFakeTimers, \"restore\">,\n\tlogger: EventAndErrorTrackingLogger,\n): {\n\tpresence: PresenceWithNotifications;\n\tprocessSignal: ProcessSignalFunction;\n\t/**\n\t * Connects presence using the client connection id provided to prepareDisconnectedPresence.\n\t */\n\tconnect: () => void;\n\t/**\n\t * The simulated local average latency used by connect.\n\t */\n\tlocalAvgLatency: number;\n} {\n\t// Ensure runtime is in disconnected state\n\truntime.clientId = undefined;\n\truntime.joined = false;\n\n\t// Remove client connection id from audience if present\n\tif (runtime.audience.getMember(clientConnectionId) !== undefined) {\n\t\truntime.removeMember(clientConnectionId);\n\t}\n\n\tconst { presence, processSignal } = createPresence(runtime, attendeeId, logger);\n\n\tconst connect = (): void => {\n\t\tconst { expectedClientJoin, updateProviders } = prepareExpectedClientJoin(\n\t\t\truntime,\n\t\t\tattendeeId,\n\t\t\tclientConnectionId,\n\t\t\tclock,\n\t\t);\n\n\t\t// Simulate connection\n\t\truntime.connect(clientConnectionId, undefined);\n\n\t\t// Validate signal was submitted\n\t\truntime.assertAllSignalsSubmitted();\n\n\t\tprocessJoinSignalAndResponse(\n\t\t\tprocessSignal,\n\t\t\texpectedClientJoin,\n\t\t\tclientConnectionId,\n\t\t\tupdateProviders,\n\t\t\tclock,\n\t\t\tlocalAvgLatency,\n\t\t);\n\t};\n\n\treturn {\n\t\tpresence,\n\t\tprocessSignal,\n\t\tconnect,\n\t\tlocalAvgLatency,\n\t};\n}\n\n/**\n * Asserts that all expected telemetry and signals were sent.\n */\nexport function assertFinalExpectations(\n\truntime: MockEphemeralRuntime,\n\tlogger: EventAndErrorTrackingLogger,\n): void {\n\t// Make sure all expected events were logged and there are no unexpected errors.\n\tconst logErrors = getUnexpectedLogErrorException(logger);\n\tif (logErrors) {\n\t\tthrow logErrors;\n\t}\n\t// Make sure all expected signals were sent.\n\truntime.assertAllSignalsSubmitted();\n}\n\n/**\n * A null validator (one that does nothing) for a given type T. It simply casts the value to\n * `JsonDeserialized<T>`.\n */\nconst nullValidator = <T extends object>(data: unknown): JsonDeserialized<T> => {\n\treturn data as JsonDeserialized<T>;\n};\n\n/**\n * Creates a spied validator for test purposes.\n *\n * @param validatorFunction - A {@link StateSchemaValidator} to wrap in a spy.\n */\nexport const createSpiedValidator = <T extends object>(\n\tvalidatorFunction: StateSchemaValidator<T> = nullValidator<T>,\n\t// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type\n) => spy(validatorFunction) satisfies StateSchemaValidator<T>;\n"]}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.MockEphemeralRuntime = exports.initialLocalClientConnectionId = void 0;
22
+ var mockEphemeralRuntime_js_1 = require("../mockEphemeralRuntime.js");
23
+ Object.defineProperty(exports, "initialLocalClientConnectionId", { enumerable: true, get: function () { return mockEphemeralRuntime_js_1.initialLocalClientConnectionId; } });
24
+ Object.defineProperty(exports, "MockEphemeralRuntime", { enumerable: true, get: function () { return mockEphemeralRuntime_js_1.MockEphemeralRuntime; } });
25
+ // eslint-disable-next-line no-restricted-syntax -- internally export all testUtils exports
26
+ __exportStar(require("../testUtils.js"), exports);
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/test/utils/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;AAEH,sEAGoC;AAFnC,yIAAA,8BAA8B,OAAA;AAC9B,+HAAA,oBAAoB,OAAA;AAGrB,2FAA2F;AAC3F,kDAAgC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport {\n\tinitialLocalClientConnectionId,\n\tMockEphemeralRuntime,\n} from \"../mockEphemeralRuntime.js\";\n\n// eslint-disable-next-line no-restricted-syntax -- internally export all testUtils exports\nexport * from \"../testUtils.js\";\n"]}
@@ -0,0 +1,37 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import type { BroadcastControls, BroadcastControlSettings } from "@fluid-internal/presence-definitions";
6
+ declare class ForcedRefreshControl implements Pick<BroadcastControls & {
7
+ forcedRefreshIntervalMs: number | undefined;
8
+ }, "forcedRefreshIntervalMs"> {
9
+ private _forcedRefreshInterval;
10
+ constructor(settings?: BroadcastControlSettings);
11
+ get forcedRefreshIntervalMs(): number | undefined;
12
+ set forcedRefreshIntervalMs(value: number | undefined);
13
+ }
14
+ /**
15
+ * Implements {@link BroadcastControls} for States Managers
16
+ * where returning `undefined` settings are allowed.
17
+ */
18
+ export declare class OptionalBroadcastControl extends ForcedRefreshControl implements BroadcastControls {
19
+ allowableUpdateLatencyMs: number | undefined;
20
+ constructor(settings?: BroadcastControlSettings);
21
+ }
22
+ /**
23
+ * Implements {@link BroadcastControls} but always provides defined value for
24
+ * {@link BroadcastControls.allowableUpdateLatencyMs | allowableUpdateLatencyMs}.
25
+ *
26
+ * If {@link BroadcastControls.allowableUpdateLatencyMs | allowableUpdateLatencyMs}
27
+ * is set to `undefined`, the default will be restored.
28
+ */
29
+ export declare class RequiredBroadcastControl extends ForcedRefreshControl implements BroadcastControls {
30
+ private readonly defaultAllowableUpdateLatencyMs;
31
+ private _allowableUpdateLatencyMs;
32
+ constructor(defaultAllowableUpdateLatencyMs: number);
33
+ get allowableUpdateLatencyMs(): number;
34
+ set allowableUpdateLatencyMs(value: number | undefined);
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=broadcastControls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcastControls.d.ts","sourceRoot":"","sources":["../../src/utils/broadcastControls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,iBAAiB,EACjB,wBAAwB,EACxB,MAAM,sCAAsC,CAAC;AAE9C,cAAM,oBACL,YACC,IAAI,CACH,iBAAiB,GAAG;IAAE,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EACnE,yBAAyB,CACzB;IAEF,OAAO,CAAC,sBAAsB,CAAqB;gBAEhC,QAAQ,CAAC,EAAE,wBAAwB;IAItD,IAAW,uBAAuB,IAAI,MAAM,GAAG,SAAS,CAEvD;IACD,IAAW,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAU3D;CACD;AAED;;;GAGG;AACH,qBAAa,wBACZ,SAAQ,oBACR,YAAW,iBAAiB;IAErB,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEjC,QAAQ,CAAC,EAAE,wBAAwB;CAItD;AAED;;;;;;GAMG;AACH,qBAAa,wBACZ,SAAQ,oBACR,YAAW,iBAAiB;IAIT,OAAO,CAAC,QAAQ,CAAC,+BAA+B;IAFnE,OAAO,CAAC,yBAAyB,CAAS;gBAEN,+BAA+B,EAAE,MAAM;IAK3E,IAAW,wBAAwB,IAAI,MAAM,CAE5C;IACD,IAAW,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAE5D;CACD"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.RequiredBroadcastControl = exports.OptionalBroadcastControl = void 0;
8
+ class ForcedRefreshControl {
9
+ constructor(settings) {
10
+ // this._forcedRefreshInterval = settings?.forcedRefreshIntervalMs;
11
+ }
12
+ get forcedRefreshIntervalMs() {
13
+ return this._forcedRefreshInterval;
14
+ }
15
+ set forcedRefreshIntervalMs(value) {
16
+ if (value === undefined) {
17
+ this._forcedRefreshInterval = undefined;
18
+ }
19
+ else {
20
+ this._forcedRefreshInterval = value >= 10 ? value : undefined;
21
+ if (value >= 10) {
22
+ // TODO: enable periodic forced refresh
23
+ throw new Error("Forced Refresh feature is not implemented");
24
+ }
25
+ }
26
+ }
27
+ }
28
+ /**
29
+ * Implements {@link BroadcastControls} for States Managers
30
+ * where returning `undefined` settings are allowed.
31
+ */
32
+ class OptionalBroadcastControl extends ForcedRefreshControl {
33
+ constructor(settings) {
34
+ super(settings);
35
+ this.allowableUpdateLatencyMs = settings?.allowableUpdateLatencyMs;
36
+ }
37
+ }
38
+ exports.OptionalBroadcastControl = OptionalBroadcastControl;
39
+ /**
40
+ * Implements {@link BroadcastControls} but always provides defined value for
41
+ * {@link BroadcastControls.allowableUpdateLatencyMs | allowableUpdateLatencyMs}.
42
+ *
43
+ * If {@link BroadcastControls.allowableUpdateLatencyMs | allowableUpdateLatencyMs}
44
+ * is set to `undefined`, the default will be restored.
45
+ */
46
+ class RequiredBroadcastControl extends ForcedRefreshControl {
47
+ constructor(defaultAllowableUpdateLatencyMs) {
48
+ super();
49
+ this.defaultAllowableUpdateLatencyMs = defaultAllowableUpdateLatencyMs;
50
+ this._allowableUpdateLatencyMs = defaultAllowableUpdateLatencyMs;
51
+ }
52
+ get allowableUpdateLatencyMs() {
53
+ return this._allowableUpdateLatencyMs;
54
+ }
55
+ set allowableUpdateLatencyMs(value) {
56
+ this._allowableUpdateLatencyMs = value ?? this.defaultAllowableUpdateLatencyMs;
57
+ }
58
+ }
59
+ exports.RequiredBroadcastControl = RequiredBroadcastControl;
60
+ //# sourceMappingURL=broadcastControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcastControls.js","sourceRoot":"","sources":["../../src/utils/broadcastControls.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAOH,MAAM,oBAAoB;IASzB,YAAmB,QAAmC;QACrD,mEAAmE;IACpE,CAAC;IAED,IAAW,uBAAuB;QACjC,OAAO,IAAI,CAAC,sBAAsB,CAAC;IACpC,CAAC;IACD,IAAW,uBAAuB,CAAC,KAAyB;QAC3D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,sBAAsB,GAAG,SAAS,CAAC;QACzC,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,sBAAsB,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9D,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;gBACjB,uCAAuC;gBACvC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;YAC9D,CAAC;QACF,CAAC;IACF,CAAC;CACD;AAED;;;GAGG;AACH,MAAa,wBACZ,SAAQ,oBAAoB;IAK5B,YAAmB,QAAmC;QACrD,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,wBAAwB,GAAG,QAAQ,EAAE,wBAAwB,CAAC;IACpE,CAAC;CACD;AAVD,4DAUC;AAED;;;;;;GAMG;AACH,MAAa,wBACZ,SAAQ,oBAAoB;IAK5B,YAAoC,+BAAuC;QAC1E,KAAK,EAAE,CAAC;QAD2B,oCAA+B,GAA/B,+BAA+B,CAAQ;QAE1E,IAAI,CAAC,yBAAyB,GAAG,+BAA+B,CAAC;IAClE,CAAC;IAED,IAAW,wBAAwB;QAClC,OAAO,IAAI,CAAC,yBAAyB,CAAC;IACvC,CAAC;IACD,IAAW,wBAAwB,CAAC,KAAyB;QAC5D,IAAI,CAAC,yBAAyB,GAAG,KAAK,IAAI,IAAI,CAAC,+BAA+B,CAAC;IAChF,CAAC;CACD;AAjBD,4DAiBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tBroadcastControls,\n\tBroadcastControlSettings,\n} from \"@fluid-internal/presence-definitions\";\n\nclass ForcedRefreshControl\n\timplements\n\t\tPick<\n\t\t\tBroadcastControls & { forcedRefreshIntervalMs: number | undefined },\n\t\t\t\"forcedRefreshIntervalMs\"\n\t\t>\n{\n\tprivate _forcedRefreshInterval: number | undefined;\n\n\tpublic constructor(settings?: BroadcastControlSettings) {\n\t\t// this._forcedRefreshInterval = settings?.forcedRefreshIntervalMs;\n\t}\n\n\tpublic get forcedRefreshIntervalMs(): number | undefined {\n\t\treturn this._forcedRefreshInterval;\n\t}\n\tpublic set forcedRefreshIntervalMs(value: number | undefined) {\n\t\tif (value === undefined) {\n\t\t\tthis._forcedRefreshInterval = undefined;\n\t\t} else {\n\t\t\tthis._forcedRefreshInterval = value >= 10 ? value : undefined;\n\t\t\tif (value >= 10) {\n\t\t\t\t// TODO: enable periodic forced refresh\n\t\t\t\tthrow new Error(\"Forced Refresh feature is not implemented\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Implements {@link BroadcastControls} for States Managers\n * where returning `undefined` settings are allowed.\n */\nexport class OptionalBroadcastControl\n\textends ForcedRefreshControl\n\timplements BroadcastControls\n{\n\tpublic allowableUpdateLatencyMs: number | undefined;\n\n\tpublic constructor(settings?: BroadcastControlSettings) {\n\t\tsuper(settings);\n\t\tthis.allowableUpdateLatencyMs = settings?.allowableUpdateLatencyMs;\n\t}\n}\n\n/**\n * Implements {@link BroadcastControls} but always provides defined value for\n * {@link BroadcastControls.allowableUpdateLatencyMs | allowableUpdateLatencyMs}.\n *\n * If {@link BroadcastControls.allowableUpdateLatencyMs | allowableUpdateLatencyMs}\n * is set to `undefined`, the default will be restored.\n */\nexport class RequiredBroadcastControl\n\textends ForcedRefreshControl\n\timplements BroadcastControls\n{\n\tprivate _allowableUpdateLatencyMs: number;\n\n\tpublic constructor(private readonly defaultAllowableUpdateLatencyMs: number) {\n\t\tsuper();\n\t\tthis._allowableUpdateLatencyMs = defaultAllowableUpdateLatencyMs;\n\t}\n\n\tpublic get allowableUpdateLatencyMs(): number {\n\t\treturn this._allowableUpdateLatencyMs;\n\t}\n\tpublic set allowableUpdateLatencyMs(value: number | undefined) {\n\t\tthis._allowableUpdateLatencyMs = value ?? this.defaultAllowableUpdateLatencyMs;\n\t}\n}\n"]}
@@ -0,0 +1,9 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ export { OptionalBroadcastControl, RequiredBroadcastControl } from "./broadcastControls.js";
6
+ export { asDeeplyReadonly, asDeeplyReadonlyDeserializedJson, type FlattenUnionWithOptionals, getOrCreateRecord, isValueRequiredState, objectEntries, objectEntriesWithoutUndefined, objectKeys, type RecordEntryTypes, revealOpaqueJson, toOpaqueJson, } from "./internalUtils.js";
7
+ export { TimerManager } from "./timerManager.js";
8
+ export { brandIVM, unbrandIVM } from "./valueManager.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAE5F,OAAO,EACN,gBAAgB,EAChB,gCAAgC,EAChC,KAAK,yBAAyB,EAC9B,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,6BAA6B,EAC7B,UAAU,EACV,KAAK,gBAAgB,EACrB,gBAAgB,EAChB,YAAY,GACZ,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.unbrandIVM = exports.brandIVM = exports.TimerManager = exports.toOpaqueJson = exports.revealOpaqueJson = exports.objectKeys = exports.objectEntriesWithoutUndefined = exports.objectEntries = exports.isValueRequiredState = exports.getOrCreateRecord = exports.asDeeplyReadonlyDeserializedJson = exports.asDeeplyReadonly = exports.RequiredBroadcastControl = exports.OptionalBroadcastControl = void 0;
8
+ var broadcastControls_js_1 = require("./broadcastControls.js");
9
+ Object.defineProperty(exports, "OptionalBroadcastControl", { enumerable: true, get: function () { return broadcastControls_js_1.OptionalBroadcastControl; } });
10
+ Object.defineProperty(exports, "RequiredBroadcastControl", { enumerable: true, get: function () { return broadcastControls_js_1.RequiredBroadcastControl; } });
11
+ var internalUtils_js_1 = require("./internalUtils.js");
12
+ Object.defineProperty(exports, "asDeeplyReadonly", { enumerable: true, get: function () { return internalUtils_js_1.asDeeplyReadonly; } });
13
+ Object.defineProperty(exports, "asDeeplyReadonlyDeserializedJson", { enumerable: true, get: function () { return internalUtils_js_1.asDeeplyReadonlyDeserializedJson; } });
14
+ Object.defineProperty(exports, "getOrCreateRecord", { enumerable: true, get: function () { return internalUtils_js_1.getOrCreateRecord; } });
15
+ Object.defineProperty(exports, "isValueRequiredState", { enumerable: true, get: function () { return internalUtils_js_1.isValueRequiredState; } });
16
+ Object.defineProperty(exports, "objectEntries", { enumerable: true, get: function () { return internalUtils_js_1.objectEntries; } });
17
+ Object.defineProperty(exports, "objectEntriesWithoutUndefined", { enumerable: true, get: function () { return internalUtils_js_1.objectEntriesWithoutUndefined; } });
18
+ Object.defineProperty(exports, "objectKeys", { enumerable: true, get: function () { return internalUtils_js_1.objectKeys; } });
19
+ Object.defineProperty(exports, "revealOpaqueJson", { enumerable: true, get: function () { return internalUtils_js_1.revealOpaqueJson; } });
20
+ Object.defineProperty(exports, "toOpaqueJson", { enumerable: true, get: function () { return internalUtils_js_1.toOpaqueJson; } });
21
+ var timerManager_js_1 = require("./timerManager.js");
22
+ Object.defineProperty(exports, "TimerManager", { enumerable: true, get: function () { return timerManager_js_1.TimerManager; } });
23
+ var valueManager_js_1 = require("./valueManager.js");
24
+ Object.defineProperty(exports, "brandIVM", { enumerable: true, get: function () { return valueManager_js_1.brandIVM; } });
25
+ Object.defineProperty(exports, "unbrandIVM", { enumerable: true, get: function () { return valueManager_js_1.unbrandIVM; } });
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAA4F;AAAnF,gIAAA,wBAAwB,OAAA;AAAE,gIAAA,wBAAwB,OAAA;AAE3D,uDAY4B;AAX3B,oHAAA,gBAAgB,OAAA;AAChB,oIAAA,gCAAgC,OAAA;AAEhC,qHAAA,iBAAiB,OAAA;AACjB,wHAAA,oBAAoB,OAAA;AACpB,iHAAA,aAAa,OAAA;AACb,iIAAA,6BAA6B,OAAA;AAC7B,8GAAA,UAAU,OAAA;AAEV,oHAAA,gBAAgB,OAAA;AAChB,gHAAA,YAAY,OAAA;AAGb,qDAAiD;AAAxC,+GAAA,YAAY,OAAA;AAErB,qDAAyD;AAAhD,2GAAA,QAAQ,OAAA;AAAE,6GAAA,UAAU,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { OptionalBroadcastControl, RequiredBroadcastControl } from \"./broadcastControls.js\";\n\nexport {\n\tasDeeplyReadonly,\n\tasDeeplyReadonlyDeserializedJson,\n\ttype FlattenUnionWithOptionals,\n\tgetOrCreateRecord,\n\tisValueRequiredState,\n\tobjectEntries,\n\tobjectEntriesWithoutUndefined,\n\tobjectKeys,\n\ttype RecordEntryTypes,\n\trevealOpaqueJson,\n\ttoOpaqueJson,\n} from \"./internalUtils.js\";\n\nexport { TimerManager } from \"./timerManager.js\";\n\nexport { brandIVM, unbrandIVM } from \"./valueManager.js\";\n"]}
@@ -0,0 +1,125 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import type { ValidatableOptionalState, ValidatableRequiredState } from "@fluid-internal/presence-definitions/internal";
6
+ import type { DeepReadonly, InternalCoreInterfacesUtilityTypes, JsonDeserialized, JsonSerializable, OpaqueJsonDeserialized, OpaqueJsonSerializable } from "@fluidframework/core-interfaces/internal";
7
+ /**
8
+ * Returns union of types of values in a record.
9
+ */
10
+ export type RecordEntryTypes<T> = T[keyof T];
11
+ type MapNumberIndicesToStrings<T> = {
12
+ [K in keyof T as K extends number ? `${K}` : K]: T[K];
13
+ };
14
+ type KeyValuePairs<T> = {
15
+ [K in keyof MapNumberIndicesToStrings<Required<T>>]: [K, Required<T>[K]];
16
+ }[keyof MapNumberIndicesToStrings<Required<T>>][];
17
+ type RequiredAndNotUndefined<T> = {
18
+ [K in keyof T]-?: Exclude<T[K], undefined>;
19
+ };
20
+ /**
21
+ * Object.entries retyped to preserve known keys and their types.
22
+ *
23
+ * @privateRemarks
24
+ * The is a defect in this utility when a string index appears in the object.
25
+ * In such a case, the only result is `[string, T]`, where `T` is the type
26
+ * of the string index entry.
27
+ */
28
+ export declare const objectEntries: <const T>(o: T) => KeyValuePairs<T>;
29
+ /**
30
+ * Object.entries retyped to preserve known keys and their types.
31
+ *
32
+ * @remarks
33
+ * Given `T` should not contain `undefined` values. If it does, use
34
+ * {@link objectEntries} instead. Without `undefined` values, this
35
+ * typing provides best handling of objects with optional properties.
36
+ */
37
+ export declare const objectEntriesWithoutUndefined: <const T>(o: T) => KeyValuePairs<RequiredAndNotUndefined<T>>;
38
+ /**
39
+ * Object.keys retyped to preserve known keys and their types.
40
+ */
41
+ export declare const objectKeys: <const T>(o: T) => (keyof MapNumberIndicesToStrings<T>)[];
42
+ /**
43
+ * Retrieve a value from a record with the given key, or create a new entry if
44
+ * the key is not in the record.
45
+ *
46
+ * @param record - The record to index/update
47
+ * @param key - The key to lookup in the record
48
+ * @param defaultValue - a function which returns a default value. This is
49
+ * called and used to set an initial value for the given key in the record if
50
+ * none exists.
51
+ * @returns either the existing value for the given key, or the newly-created
52
+ * value (the result of `defaultValue`)
53
+ */
54
+ export declare function getOrCreateRecord<const K extends string | number | symbol, const V>(record: Record<K, V>, key: K, defaultValue: (key: K) => V): V;
55
+ /**
56
+ * No-runtime-effect helper to apply deep immutability to a value's type.
57
+ */
58
+ export declare function asDeeplyReadonly<T>(value: T): DeepReadonly<T>;
59
+ export declare function asDeeplyReadonlyDeserializedJson<T>(value: OpaqueJsonDeserialized<T>): DeepReadonly<JsonDeserialized<T>>;
60
+ export declare function asDeeplyReadonlyDeserializedJson<T>(value: OpaqueJsonDeserialized<T> | undefined): DeepReadonly<JsonDeserialized<T>> | undefined;
61
+ /**
62
+ * Conditional type that reveals the underlying JSON type of an opaque JSON value. If `T` is an object, the key values
63
+ * will be revealed.
64
+ */
65
+ type RevealOpaqueJsonDeserialized<T> = T extends OpaqueJsonDeserialized<infer U> ? JsonDeserialized<U> : {
66
+ [Key in keyof T]: RevealOpaqueJsonDeserialized<T[Key]>;
67
+ };
68
+ /**
69
+ * No-runtime-effect helper to reveal the JSON type from a value's opaque JSON
70
+ * types throughout a structure.
71
+ *
72
+ * @remarks
73
+ * {@link OpaqueJsonDeserialized} instances will be replaced shallowly such
74
+ * that nested instances are retained.
75
+ */
76
+ export declare function revealOpaqueJson<T>(value: T): RevealOpaqueJsonDeserialized<T>;
77
+ /**
78
+ * No-runtime-effect helper to automatically cast JSON type to Opaque JSON type
79
+ * at outermost scope.
80
+ *
81
+ * @remarks
82
+ * Types that satisfy {@link JsonSerializable} may also be deserialized. Thus,
83
+ * the return type is both {@link OpaqueJsonSerializable} and
84
+ * {@link OpaqueJsonDeserialized}.
85
+ */
86
+ export declare function toOpaqueJson<const T>(value: JsonSerializable<T>): OpaqueJsonSerializable<T> & OpaqueJsonDeserialized<T>;
87
+ /**
88
+ * Convert a union of types to an intersection of those types.
89
+ *
90
+ * @privateRemarks
91
+ * First an always true extends clause is used (T extends T) to distribute T
92
+ * into to a union of types contravariant over each member of the T union.
93
+ * Then the constraint on the type parameter in this new context is inferred,
94
+ * giving the intersection.
95
+ *
96
+ * Future: This definition is identical to one in `packages/dds/tree/src/util/typeUtils.ts`
97
+ * and should be consolidated.
98
+ */
99
+ type UnionToIntersection<T> = (T extends T ? (k: T) => unknown : never) extends (k: infer U) => unknown ? U : never;
100
+ /**
101
+ * Generates a union of types that are the remainder from a simple
102
+ * Pick combination (that is the set of common properties).
103
+ */
104
+ type PickRemainder<T> = Pick<T, keyof T> extends infer Common ? T extends unknown ? Omit<T, keyof Common> : never : never;
105
+ /**
106
+ * Combines union of structure into a single structure where common properties
107
+ * are unions of their respective types and optional properties are defined for
108
+ * properties that are not common to each union member.
109
+ *
110
+ * @remarks
111
+ * If a property is common to multiple, but not all union member and the
112
+ * types are incompatible, the resulting type will be `never` for that
113
+ * property. (This can be fixed, but might be best addressed by changing
114
+ * T to be a tuple of types to be combined.)
115
+ */
116
+ export type FlattenUnionWithOptionals<T> = InternalCoreInterfacesUtilityTypes.FlattenIntersection<Pick<T, keyof T> & UnionToIntersection<Partial<PickRemainder<T>>>>;
117
+ /**
118
+ * Type guard to check if a state is a required state (has a value).
119
+ *
120
+ * @param state - The state to check
121
+ * @returns True if the state has a value and is therefore a {@link ValidatableRequiredState}
122
+ */
123
+ export declare function isValueRequiredState<T>(state: ValidatableRequiredState<T> | ValidatableOptionalState<T>): state is ValidatableRequiredState<T>;
124
+ export {};
125
+ //# sourceMappingURL=internalUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internalUtils.d.ts","sourceRoot":"","sources":["../../src/utils/internalUtils.ts"],"names":[],"mappings":"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"}