@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,246 @@
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
+ const node_assert_1 = require("node:assert");
8
+ const internal_1 = require("@fluidframework/test-utils/internal");
9
+ const mocha_1 = require("mocha");
10
+ const sinon_1 = require("sinon");
11
+ const test_1 = require("@fluid-internal/presence-runtime/internal/test");
12
+ const states_1 = require("@fluid-internal/presence-runtime/states");
13
+ const utils_1 = require("@fluid-internal/presence-runtime/utils");
14
+ const mockEphemeralRuntime_js_1 = require("../mockEphemeralRuntime.js");
15
+ const testUtils_js_1 = require("../testUtils.js");
16
+ (0, mocha_1.describe)("Presence/States", () => {
17
+ (0, mocha_1.describe)("Runtime schema validation", () => {
18
+ const afterCleanUp = [];
19
+ const initialTime = 500;
20
+ const attendee1ValueRevisionTimestamp = 600;
21
+ const testStartTime = 1010;
22
+ let localAttendee1ValueRevisionTimestamp;
23
+ let clock;
24
+ let logger;
25
+ let presence;
26
+ let processSignal;
27
+ let runtime;
28
+ (0, mocha_1.before)(async () => {
29
+ clock = (0, sinon_1.useFakeTimers)();
30
+ });
31
+ (0, mocha_1.beforeEach)(() => {
32
+ logger = new internal_1.EventAndErrorTrackingLogger();
33
+ runtime = new mockEphemeralRuntime_js_1.MockEphemeralRuntime(logger);
34
+ clock.setSystemTime(initialTime);
35
+ let localAvgLatency;
36
+ ({ presence, processSignal, localAvgLatency } = (0, testUtils_js_1.prepareConnectedPresence)(runtime, testUtils_js_1.localAttendeeId, testUtils_js_1.initialLocalClientConnectionId, clock, logger));
37
+ // Note that while the initialTime was set to 500, the prepareConnectedPresence call advances
38
+ // it. Set a consistent start time for all tests.
39
+ const deltaToStart = testStartTime - clock.now;
40
+ (0, node_assert_1.strict)(deltaToStart >= 10);
41
+ clock.tick(deltaToStart - 10);
42
+ // Process remote client update signal (attendeeId-1 is then part of local client's known session).
43
+ const attendee1UpdateSendTimestamp = deltaToStart - 20;
44
+ const attendee1AvgLatency = 20;
45
+ const attendee1ToLocalTimeDelta = clock.now - (localAvgLatency + attendee1AvgLatency + attendee1UpdateSendTimestamp);
46
+ localAttendee1ValueRevisionTimestamp =
47
+ attendee1ValueRevisionTimestamp + attendee1ToLocalTimeDelta;
48
+ processSignal([], {
49
+ type: "Pres:DatastoreUpdate",
50
+ content: {
51
+ sendTimestamp: attendee1UpdateSendTimestamp,
52
+ avgLatency: attendee1AvgLatency,
53
+ data: {
54
+ "system:presence": {
55
+ "clientToSessionId": {
56
+ "client1": {
57
+ "rev": 0,
58
+ "timestamp": initialTime + 40,
59
+ "value": testUtils_js_1.attendeeId1,
60
+ },
61
+ },
62
+ },
63
+ "s:name:testWorkspace": {
64
+ "latest": {
65
+ [testUtils_js_1.attendeeId1]: {
66
+ "rev": 1,
67
+ "timestamp": attendee1ValueRevisionTimestamp,
68
+ "value": (0, utils_1.toOpaqueJson)({ x: 1, y: 1, z: 1 }),
69
+ },
70
+ },
71
+ "latestMap": {
72
+ [testUtils_js_1.attendeeId1]: {
73
+ "rev": 1,
74
+ "items": {
75
+ "key1": {
76
+ "rev": 1,
77
+ "timestamp": attendee1ValueRevisionTimestamp,
78
+ "value": (0, utils_1.toOpaqueJson)({ a: 1, b: 1 }),
79
+ },
80
+ "key2": {
81
+ "rev": 1,
82
+ "timestamp": attendee1ValueRevisionTimestamp,
83
+ // out of schema value
84
+ "value": (0, utils_1.toOpaqueJson)({ b: 1, d: 1 }),
85
+ },
86
+ },
87
+ },
88
+ },
89
+ },
90
+ },
91
+ },
92
+ clientId: "client1",
93
+ }, false);
94
+ // Pass a little time (to mimic reality)
95
+ clock.tick(10);
96
+ });
97
+ (0, mocha_1.afterEach)(function (done) {
98
+ clock.reset();
99
+ // If the test passed so far, check final expectations.
100
+ if (this.currentTest?.state === "passed") {
101
+ (0, testUtils_js_1.assertFinalExpectations)(runtime, logger);
102
+ }
103
+ for (const cleanUp of afterCleanUp) {
104
+ cleanUp();
105
+ }
106
+ afterCleanUp.length = 0;
107
+ done();
108
+ });
109
+ (0, mocha_1.after)(() => {
110
+ clock.restore();
111
+ });
112
+ (0, mocha_1.describe)("response to Join signal", () => {
113
+ (0, mocha_1.it)("does not contain validation metadata for remote clients", () => {
114
+ // Setup
115
+ // Check Join response without active validators
116
+ const attendeeId4 = (0, testUtils_js_1.createSpecificAttendeeId)("attendeeId-4");
117
+ const connectionId4 = "client4";
118
+ const client4JoinTime = clock.now - 50;
119
+ const newAttendeeSignal = (0, testUtils_js_1.generateBasicClientJoin)(client4JoinTime, {
120
+ averageLatency: 50,
121
+ attendeeId: attendeeId4,
122
+ clientConnectionId: connectionId4,
123
+ updateProviders: [testUtils_js_1.initialLocalClientConnectionId],
124
+ });
125
+ const expectedSetupJoinResponse = {
126
+ type: "Pres:DatastoreUpdate",
127
+ content: {
128
+ "avgLatency": 10,
129
+ "data": {
130
+ "system:presence": {
131
+ "clientToSessionId": {
132
+ [testUtils_js_1.initialLocalClientConnectionId]: {
133
+ "rev": 0,
134
+ "timestamp": initialTime,
135
+ "value": testUtils_js_1.localAttendeeId,
136
+ },
137
+ [testUtils_js_1.connectionId1]: {
138
+ "rev": 0,
139
+ "timestamp": initialTime + 40,
140
+ "value": testUtils_js_1.attendeeId1,
141
+ },
142
+ [connectionId4]: {
143
+ "rev": 0,
144
+ "timestamp": client4JoinTime,
145
+ "value": attendeeId4,
146
+ },
147
+ },
148
+ },
149
+ "s:name:testWorkspace": {
150
+ "latest": {
151
+ [testUtils_js_1.attendeeId1]: {
152
+ "rev": 1,
153
+ "timestamp": localAttendee1ValueRevisionTimestamp,
154
+ "value": (0, utils_1.toOpaqueJson)({ x: 1, y: 1, z: 1 }),
155
+ },
156
+ },
157
+ "latestMap": {
158
+ [testUtils_js_1.attendeeId1]: {
159
+ "rev": 1,
160
+ "items": {
161
+ "key1": {
162
+ "rev": 1,
163
+ "timestamp": localAttendee1ValueRevisionTimestamp,
164
+ "value": (0, utils_1.toOpaqueJson)({ a: 1, b: 1 }),
165
+ },
166
+ "key2": {
167
+ "rev": 1,
168
+ "timestamp": localAttendee1ValueRevisionTimestamp,
169
+ "value": (0, utils_1.toOpaqueJson)({ b: 1, d: 1 }),
170
+ },
171
+ },
172
+ },
173
+ },
174
+ },
175
+ },
176
+ "isComplete": true,
177
+ "joinResponseFor": [connectionId4],
178
+ "sendTimestamp": clock.now + test_1.broadcastJoinResponseDelaysMs.namedResponder,
179
+ },
180
+ };
181
+ {
182
+ runtime.signalsExpected.push([expectedSetupJoinResponse]);
183
+ processSignal([], newAttendeeSignal, false);
184
+ clock.tick(test_1.broadcastJoinResponseDelaysMs.namedResponder);
185
+ }
186
+ // Pass a little time (to distinguish between signals)
187
+ clock.tick(10);
188
+ // Create State objects with validators
189
+ const workspaceSetupTime = clock.now;
190
+ const point3DValidatorFunction = (0, testUtils_js_1.createSpiedValidator)((d) => {
191
+ return typeof d === "object" ? d : undefined;
192
+ });
193
+ const statesWorkspace = presence.states.getWorkspace("name:testWorkspace", {
194
+ latest: states_1.StateFactory.latest({
195
+ local: { x: 0, y: 0, z: 0 },
196
+ validator: point3DValidatorFunction,
197
+ settings: {
198
+ // To prevent sending messages ahead of full broadcast from
199
+ // join below, set the allowable latency to twice expected
200
+ // join response time.
201
+ allowableUpdateLatencyMs: 2 * test_1.broadcastJoinResponseDelaysMs.namedResponder,
202
+ },
203
+ }),
204
+ });
205
+ const latest = statesWorkspace.states.latest;
206
+ const attendee1 = presence.attendees.getAttendee(testUtils_js_1.attendeeId1);
207
+ latest.getRemote(attendee1)?.value();
208
+ const originalJoinResponseData = expectedSetupJoinResponse.content.data;
209
+ const expectedJoinResponse = {
210
+ type: "Pres:DatastoreUpdate",
211
+ content: {
212
+ "avgLatency": 10,
213
+ "data": {
214
+ "system:presence": {
215
+ "clientToSessionId": {
216
+ ...originalJoinResponseData["system:presence"].clientToSessionId,
217
+ },
218
+ },
219
+ "s:name:testWorkspace": {
220
+ "latest": {
221
+ ...originalJoinResponseData["s:name:testWorkspace"].latest,
222
+ [testUtils_js_1.localAttendeeId]: {
223
+ "rev": 0,
224
+ "timestamp": workspaceSetupTime,
225
+ "value": (0, utils_1.toOpaqueJson)({ x: 0, y: 0, z: 0 }),
226
+ },
227
+ },
228
+ "latestMap": {
229
+ ...originalJoinResponseData["s:name:testWorkspace"].latestMap,
230
+ },
231
+ },
232
+ },
233
+ "isComplete": true,
234
+ "joinResponseFor": [connectionId4],
235
+ "sendTimestamp": clock.now + test_1.broadcastJoinResponseDelaysMs.namedResponder,
236
+ },
237
+ };
238
+ runtime.signalsExpected.push([expectedJoinResponse]);
239
+ // Act & Verify - resend new attendee Join signal
240
+ processSignal([], newAttendeeSignal, false);
241
+ clock.tick(test_1.broadcastJoinResponseDelaysMs.namedResponder);
242
+ });
243
+ });
244
+ });
245
+ });
246
+ //# sourceMappingURL=protocol.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.spec.js","sourceRoot":"","sources":["../../../../src/states/test/schemaValidation/protocol.spec.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 { strict as assert } from \"node:assert\";\n\nimport type { PresenceWithNotifications } from \"@fluid-internal/presence-definitions\";\nimport { EventAndErrorTrackingLogger } from \"@fluidframework/test-utils/internal\";\nimport { describe, it, after, afterEach, before, beforeEach } from \"mocha\";\nimport { useFakeTimers, type SinonFakeTimers } from \"sinon\";\n\nimport type { OutboundDatastoreUpdateMessage } from \"@fluid-internal/presence-runtime/internal/test\";\nimport { broadcastJoinResponseDelaysMs } from \"@fluid-internal/presence-runtime/internal/test\";\nimport { StateFactory } from \"@fluid-internal/presence-runtime/states\";\nimport { toOpaqueJson } from \"@fluid-internal/presence-runtime/utils\";\n\nimport { MockEphemeralRuntime } from \"../mockEphemeralRuntime.js\";\nimport type { ProcessSignalFunction } from \"../testUtils.js\";\nimport {\n\tassertFinalExpectations,\n\tattendeeId1,\n\tlocalAttendeeId,\n\tconnectionId1,\n\tinitialLocalClientConnectionId,\n\tcreateSpecificAttendeeId,\n\tcreateSpiedValidator,\n\tgenerateBasicClientJoin,\n\tprepareConnectedPresence,\n} from \"../testUtils.js\";\n\n/**\n * Workspace updates\n */\ninterface Point3D {\n\tx: number;\n\ty: number;\n\tz: number;\n}\n\ndescribe(\"Presence/States\", () => {\n\tdescribe(\"Runtime schema validation\", () => {\n\t\tconst afterCleanUp: (() => void)[] = [];\n\t\tconst initialTime = 500;\n\t\tconst attendee1ValueRevisionTimestamp = 600;\n\t\tconst testStartTime = 1010;\n\t\tlet localAttendee1ValueRevisionTimestamp: number;\n\n\t\tlet clock: SinonFakeTimers;\n\t\tlet logger: EventAndErrorTrackingLogger;\n\t\tlet presence: PresenceWithNotifications;\n\t\tlet processSignal: ProcessSignalFunction;\n\t\tlet runtime: MockEphemeralRuntime;\n\n\t\tbefore(async () => {\n\t\t\tclock = useFakeTimers();\n\t\t});\n\n\t\tbeforeEach(() => {\n\t\t\tlogger = new EventAndErrorTrackingLogger();\n\t\t\truntime = new MockEphemeralRuntime(logger);\n\t\t\tclock.setSystemTime(initialTime);\n\n\t\t\tlet localAvgLatency: number;\n\t\t\t({ presence, processSignal, localAvgLatency } = prepareConnectedPresence(\n\t\t\t\truntime,\n\t\t\t\tlocalAttendeeId,\n\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\tclock,\n\t\t\t\tlogger,\n\t\t\t));\n\n\t\t\t// Note that while the initialTime was set to 500, the prepareConnectedPresence call advances\n\t\t\t// it. Set a consistent start time for all tests.\n\t\t\tconst deltaToStart = testStartTime - clock.now;\n\t\t\tassert(deltaToStart >= 10);\n\t\t\tclock.tick(deltaToStart - 10);\n\n\t\t\t// Process remote client update signal (attendeeId-1 is then part of local client's known session).\n\t\t\tconst attendee1UpdateSendTimestamp = deltaToStart - 20;\n\t\t\tconst attendee1AvgLatency = 20;\n\t\t\tconst attendee1ToLocalTimeDelta =\n\t\t\t\tclock.now - (localAvgLatency + attendee1AvgLatency + attendee1UpdateSendTimestamp);\n\t\t\tlocalAttendee1ValueRevisionTimestamp =\n\t\t\t\tattendee1ValueRevisionTimestamp + attendee1ToLocalTimeDelta;\n\t\t\tprocessSignal(\n\t\t\t\t[],\n\t\t\t\t{\n\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\tsendTimestamp: attendee1UpdateSendTimestamp,\n\t\t\t\t\t\tavgLatency: attendee1AvgLatency,\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t\t\t\t\"client1\": {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": initialTime + 40,\n\t\t\t\t\t\t\t\t\t\t\"value\": attendeeId1,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\"latest\": {\n\t\t\t\t\t\t\t\t\t[attendeeId1]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": attendee1ValueRevisionTimestamp,\n\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 1, y: 1, z: 1 }),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"latestMap\": {\n\t\t\t\t\t\t\t\t\t[attendeeId1]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\"key1\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": attendee1ValueRevisionTimestamp,\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ a: 1, b: 1 }),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"key2\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": attendee1ValueRevisionTimestamp,\n\t\t\t\t\t\t\t\t\t\t\t\t// out of schema value\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ b: 1, d: 1 }),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tclientId: \"client1\",\n\t\t\t\t},\n\t\t\t\tfalse,\n\t\t\t);\n\n\t\t\t// Pass a little time (to mimic reality)\n\t\t\tclock.tick(10);\n\t\t});\n\n\t\tafterEach(function (done: Mocha.Done) {\n\t\t\tclock.reset();\n\n\t\t\t// If the test passed so far, check final expectations.\n\t\t\tif (this.currentTest?.state === \"passed\") {\n\t\t\t\tassertFinalExpectations(runtime, logger);\n\t\t\t}\n\n\t\t\tfor (const cleanUp of afterCleanUp) {\n\t\t\t\tcleanUp();\n\t\t\t}\n\t\t\tafterCleanUp.length = 0;\n\t\t\tdone();\n\t\t});\n\n\t\tafter(() => {\n\t\t\tclock.restore();\n\t\t});\n\n\t\tdescribe(\"response to Join signal\", () => {\n\t\t\tit(\"does not contain validation metadata for remote clients\", () => {\n\t\t\t\t// Setup\n\n\t\t\t\t// Check Join response without active validators\n\t\t\t\tconst attendeeId4 = createSpecificAttendeeId(\"attendeeId-4\");\n\t\t\t\tconst connectionId4 = \"client4\";\n\t\t\t\tconst client4JoinTime = clock.now - 50;\n\t\t\t\tconst newAttendeeSignal = generateBasicClientJoin(client4JoinTime, {\n\t\t\t\t\taverageLatency: 50,\n\t\t\t\t\tattendeeId: attendeeId4,\n\t\t\t\t\tclientConnectionId: connectionId4,\n\t\t\t\t\tupdateProviders: [initialLocalClientConnectionId],\n\t\t\t\t});\n\t\t\t\tconst expectedSetupJoinResponse = {\n\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"avgLatency\": 10,\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t\t\t\t[initialLocalClientConnectionId]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": initialTime,\n\t\t\t\t\t\t\t\t\t\t\"value\": localAttendeeId,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t[connectionId1]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": initialTime + 40,\n\t\t\t\t\t\t\t\t\t\t\"value\": attendeeId1,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t[connectionId4]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": client4JoinTime,\n\t\t\t\t\t\t\t\t\t\t\"value\": attendeeId4,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\"latest\": {\n\t\t\t\t\t\t\t\t\t[attendeeId1]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": localAttendee1ValueRevisionTimestamp,\n\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 1, y: 1, z: 1 }),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"latestMap\": {\n\t\t\t\t\t\t\t\t\t[attendeeId1]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\"items\": {\n\t\t\t\t\t\t\t\t\t\t\t\"key1\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": localAttendee1ValueRevisionTimestamp,\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ a: 1, b: 1 }),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\"key2\": {\n\t\t\t\t\t\t\t\t\t\t\t\t\"rev\": 1,\n\t\t\t\t\t\t\t\t\t\t\t\t\"timestamp\": localAttendee1ValueRevisionTimestamp,\n\t\t\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ b: 1, d: 1 }),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"isComplete\": true,\n\t\t\t\t\t\t\"joinResponseFor\": [connectionId4],\n\t\t\t\t\t\t\"sendTimestamp\": clock.now + broadcastJoinResponseDelaysMs.namedResponder,\n\t\t\t\t\t},\n\t\t\t\t} as const satisfies OutboundDatastoreUpdateMessage;\n\t\t\t\t{\n\t\t\t\t\truntime.signalsExpected.push([expectedSetupJoinResponse]);\n\t\t\t\t\tprocessSignal([], newAttendeeSignal, false);\n\t\t\t\t\tclock.tick(broadcastJoinResponseDelaysMs.namedResponder);\n\t\t\t\t}\n\t\t\t\t// Pass a little time (to distinguish between signals)\n\t\t\t\tclock.tick(10);\n\n\t\t\t\t// Create State objects with validators\n\t\t\t\tconst workspaceSetupTime = clock.now;\n\t\t\t\tconst point3DValidatorFunction = createSpiedValidator<Point3D>((d: unknown) => {\n\t\t\t\t\treturn typeof d === \"object\" ? (d as Point3D) : undefined;\n\t\t\t\t});\n\t\t\t\tconst statesWorkspace = presence.states.getWorkspace(\"name:testWorkspace\", {\n\t\t\t\t\tlatest: StateFactory.latest({\n\t\t\t\t\t\tlocal: { x: 0, y: 0, z: 0 },\n\t\t\t\t\t\tvalidator: point3DValidatorFunction,\n\t\t\t\t\t\tsettings: {\n\t\t\t\t\t\t\t// To prevent sending messages ahead of full broadcast from\n\t\t\t\t\t\t\t// join below, set the allowable latency to twice expected\n\t\t\t\t\t\t\t// join response time.\n\t\t\t\t\t\t\tallowableUpdateLatencyMs: 2 * broadcastJoinResponseDelaysMs.namedResponder,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tconst latest = statesWorkspace.states.latest;\n\t\t\t\tconst attendee1 = presence.attendees.getAttendee(attendeeId1);\n\n\t\t\t\tlatest.getRemote(attendee1)?.value();\n\n\t\t\t\tconst originalJoinResponseData = expectedSetupJoinResponse.content.data;\n\t\t\t\tconst expectedJoinResponse = {\n\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"avgLatency\": 10,\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\"clientToSessionId\": {\n\t\t\t\t\t\t\t\t\t...originalJoinResponseData[\"system:presence\"].clientToSessionId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"s:name:testWorkspace\": {\n\t\t\t\t\t\t\t\t\"latest\": {\n\t\t\t\t\t\t\t\t\t...originalJoinResponseData[\"s:name:testWorkspace\"].latest,\n\t\t\t\t\t\t\t\t\t[localAttendeeId]: {\n\t\t\t\t\t\t\t\t\t\t\"rev\": 0,\n\t\t\t\t\t\t\t\t\t\t\"timestamp\": workspaceSetupTime,\n\t\t\t\t\t\t\t\t\t\t\"value\": toOpaqueJson({ x: 0, y: 0, z: 0 }),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"latestMap\": {\n\t\t\t\t\t\t\t\t\t...originalJoinResponseData[\"s:name:testWorkspace\"].latestMap,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"isComplete\": true,\n\t\t\t\t\t\t\"joinResponseFor\": [connectionId4],\n\t\t\t\t\t\t\"sendTimestamp\": clock.now + broadcastJoinResponseDelaysMs.namedResponder,\n\t\t\t\t\t},\n\t\t\t\t} as const satisfies OutboundDatastoreUpdateMessage;\n\t\t\t\truntime.signalsExpected.push([expectedJoinResponse]);\n\n\t\t\t\t// Act & Verify - resend new attendee Join signal\n\t\t\t\tprocessSignal([], newAttendeeSignal, false);\n\t\t\t\tclock.tick(broadcastJoinResponseDelaysMs.namedResponder);\n\t\t\t});\n\t\t});\n\t});\n});\n"]}