@fluidframework/merge-tree 2.30.0 → 2.31.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 (308) hide show
  1. package/CHANGELOG.md +403 -399
  2. package/api-report/merge-tree.legacy.alpha.api.md +1 -0
  3. package/dist/MergeTreeTextHelper.d.ts +9 -3
  4. package/dist/MergeTreeTextHelper.d.ts.map +1 -1
  5. package/dist/MergeTreeTextHelper.js +5 -5
  6. package/dist/MergeTreeTextHelper.js.map +1 -1
  7. package/dist/client.d.ts +7 -13
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +136 -110
  10. package/dist/client.js.map +1 -1
  11. package/dist/endOfTreeSegment.d.ts +12 -8
  12. package/dist/endOfTreeSegment.d.ts.map +1 -1
  13. package/dist/endOfTreeSegment.js +2 -4
  14. package/dist/endOfTreeSegment.js.map +1 -1
  15. package/dist/index.d.ts +6 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -3
  18. package/dist/index.js.map +1 -1
  19. package/dist/mergeTree.d.ts +37 -23
  20. package/dist/mergeTree.d.ts.map +1 -1
  21. package/dist/mergeTree.js +400 -483
  22. package/dist/mergeTree.js.map +1 -1
  23. package/dist/mergeTreeDeltaCallback.d.ts +4 -8
  24. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  25. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  26. package/dist/mergeTreeNodes.d.ts +32 -10
  27. package/dist/mergeTreeNodes.d.ts.map +1 -1
  28. package/dist/mergeTreeNodes.js +43 -28
  29. package/dist/mergeTreeNodes.js.map +1 -1
  30. package/dist/partialLengths.d.ts +2 -2
  31. package/dist/partialLengths.d.ts.map +1 -1
  32. package/dist/partialLengths.js +181 -109
  33. package/dist/partialLengths.js.map +1 -1
  34. package/dist/perspective.d.ts +8 -27
  35. package/dist/perspective.d.ts.map +1 -1
  36. package/dist/perspective.js +7 -67
  37. package/dist/perspective.js.map +1 -1
  38. package/dist/revertibles.d.ts.map +1 -1
  39. package/dist/revertibles.js +2 -2
  40. package/dist/revertibles.js.map +1 -1
  41. package/dist/segmentInfos.d.ts +20 -106
  42. package/dist/segmentInfos.d.ts.map +1 -1
  43. package/dist/segmentInfos.js +28 -42
  44. package/dist/segmentInfos.js.map +1 -1
  45. package/dist/segmentPropertiesManager.d.ts +1 -14
  46. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  47. package/dist/segmentPropertiesManager.js +3 -17
  48. package/dist/segmentPropertiesManager.js.map +1 -1
  49. package/dist/snapshotLoader.d.ts.map +1 -1
  50. package/dist/snapshotLoader.js +62 -19
  51. package/dist/snapshotLoader.js.map +1 -1
  52. package/dist/snapshotV1.d.ts.map +1 -1
  53. package/dist/snapshotV1.js +55 -24
  54. package/dist/snapshotV1.js.map +1 -1
  55. package/dist/snapshotlegacy.d.ts.map +1 -1
  56. package/dist/snapshotlegacy.js +6 -9
  57. package/dist/snapshotlegacy.js.map +1 -1
  58. package/dist/stamps.d.ts +1 -1
  59. package/dist/stamps.js +1 -1
  60. package/dist/stamps.js.map +1 -1
  61. package/dist/test/Insertion.perf.spec.js +6 -51
  62. package/dist/test/Insertion.perf.spec.js.map +1 -1
  63. package/dist/test/PartialLengths.perf.spec.js +18 -25
  64. package/dist/test/PartialLengths.perf.spec.js.map +1 -1
  65. package/dist/test/Removal.perf.spec.js +13 -41
  66. package/dist/test/Removal.perf.spec.js.map +1 -1
  67. package/dist/test/beastTest.spec.d.ts.map +1 -1
  68. package/dist/test/beastTest.spec.js +41 -66
  69. package/dist/test/beastTest.spec.js.map +1 -1
  70. package/dist/test/client.annotateMarker.spec.js +1 -11
  71. package/dist/test/client.annotateMarker.spec.js.map +1 -1
  72. package/dist/test/client.applyMsg.spec.js +14 -14
  73. package/dist/test/client.applyMsg.spec.js.map +1 -1
  74. package/dist/test/client.getPosition.spec.js +1 -1
  75. package/dist/test/client.getPosition.spec.js.map +1 -1
  76. package/dist/test/client.localReference.spec.js +1 -1
  77. package/dist/test/client.localReference.spec.js.map +1 -1
  78. package/dist/test/client.rollback.spec.js +49 -58
  79. package/dist/test/client.rollback.spec.js.map +1 -1
  80. package/dist/test/client.rollbackFarm.spec.js +1 -1
  81. package/dist/test/client.rollbackFarm.spec.js.map +1 -1
  82. package/dist/test/client.searchForMarker.spec.js +4 -21
  83. package/dist/test/client.searchForMarker.spec.js.map +1 -1
  84. package/dist/test/index.d.ts +2 -2
  85. package/dist/test/index.d.ts.map +1 -1
  86. package/dist/test/index.js +2 -6
  87. package/dist/test/index.js.map +1 -1
  88. package/dist/test/mergeTree.annotate.deltaCallback.spec.js +14 -59
  89. package/dist/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
  90. package/dist/test/mergeTree.annotate.spec.js +47 -63
  91. package/dist/test/mergeTree.annotate.spec.js.map +1 -1
  92. package/dist/test/mergeTree.insert.deltaCallback.spec.js +9 -62
  93. package/dist/test/mergeTree.insert.deltaCallback.spec.js.map +1 -1
  94. package/dist/test/mergeTree.insertingWalk.spec.js +59 -125
  95. package/dist/test/mergeTree.insertingWalk.spec.js.map +1 -1
  96. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +12 -93
  97. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
  98. package/dist/test/mergeTree.markRangeRemoved.spec.js +10 -7
  99. package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  100. package/dist/test/mergeTree.walk.spec.js +2 -14
  101. package/dist/test/mergeTree.walk.spec.js.map +1 -1
  102. package/dist/test/mergeTreeOperationRunner.js +2 -2
  103. package/dist/test/mergeTreeOperationRunner.js.map +1 -1
  104. package/dist/test/obliterate.concurrent.spec.js +18 -23
  105. package/dist/test/obliterate.concurrent.spec.js.map +1 -1
  106. package/dist/test/obliterate.partialLength.spec.js +166 -136
  107. package/dist/test/obliterate.partialLength.spec.js.map +1 -1
  108. package/dist/test/obliterate.spec.js +16 -126
  109. package/dist/test/obliterate.spec.js.map +1 -1
  110. package/dist/test/partialLength.spec.js +28 -196
  111. package/dist/test/partialLength.spec.js.map +1 -1
  112. package/dist/test/perspective.spec.js +34 -0
  113. package/dist/test/perspective.spec.js.map +1 -1
  114. package/dist/test/propertyManager.spec.js +1 -1
  115. package/dist/test/propertyManager.spec.js.map +1 -1
  116. package/dist/test/resetPendingSegmentsToOp.spec.js +0 -2
  117. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  118. package/dist/test/segmentGroupCollection.spec.js +10 -4
  119. package/dist/test/segmentGroupCollection.spec.js.map +1 -1
  120. package/dist/test/testClient.d.ts +1 -0
  121. package/dist/test/testClient.d.ts.map +1 -1
  122. package/dist/test/testClient.js +16 -26
  123. package/dist/test/testClient.js.map +1 -1
  124. package/dist/test/testClientLogger.d.ts.map +1 -1
  125. package/dist/test/testClientLogger.js +3 -10
  126. package/dist/test/testClientLogger.js.map +1 -1
  127. package/dist/test/testServer.d.ts +2 -1
  128. package/dist/test/testServer.d.ts.map +1 -1
  129. package/dist/test/testServer.js +7 -5
  130. package/dist/test/testServer.js.map +1 -1
  131. package/dist/test/testUtils.d.ts +36 -56
  132. package/dist/test/testUtils.d.ts.map +1 -1
  133. package/dist/test/testUtils.js +68 -77
  134. package/dist/test/testUtils.js.map +1 -1
  135. package/dist/test/text.d.ts +2 -2
  136. package/dist/test/text.d.ts.map +1 -1
  137. package/dist/test/text.js +5 -2
  138. package/dist/test/text.js.map +1 -1
  139. package/dist/textSegment.d.ts +0 -6
  140. package/dist/textSegment.d.ts.map +1 -1
  141. package/dist/textSegment.js.map +1 -1
  142. package/dist/zamboni.d.ts.map +1 -1
  143. package/dist/zamboni.js +53 -26
  144. package/dist/zamboni.js.map +1 -1
  145. package/lib/MergeTreeTextHelper.d.ts +9 -3
  146. package/lib/MergeTreeTextHelper.d.ts.map +1 -1
  147. package/lib/MergeTreeTextHelper.js +5 -5
  148. package/lib/MergeTreeTextHelper.js.map +1 -1
  149. package/lib/client.d.ts +7 -13
  150. package/lib/client.d.ts.map +1 -1
  151. package/lib/client.js +117 -116
  152. package/lib/client.js.map +1 -1
  153. package/lib/endOfTreeSegment.d.ts +12 -8
  154. package/lib/endOfTreeSegment.d.ts.map +1 -1
  155. package/lib/endOfTreeSegment.js +2 -4
  156. package/lib/endOfTreeSegment.js.map +1 -1
  157. package/lib/index.d.ts +6 -3
  158. package/lib/index.d.ts.map +1 -1
  159. package/lib/index.js +1 -1
  160. package/lib/index.js.map +1 -1
  161. package/lib/mergeTree.d.ts +37 -23
  162. package/lib/mergeTree.d.ts.map +1 -1
  163. package/lib/mergeTree.js +381 -488
  164. package/lib/mergeTree.js.map +1 -1
  165. package/lib/mergeTreeDeltaCallback.d.ts +4 -8
  166. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  167. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  168. package/lib/mergeTreeNodes.d.ts +32 -10
  169. package/lib/mergeTreeNodes.d.ts.map +1 -1
  170. package/lib/mergeTreeNodes.js +42 -29
  171. package/lib/mergeTreeNodes.js.map +1 -1
  172. package/lib/partialLengths.d.ts +2 -2
  173. package/lib/partialLengths.d.ts.map +1 -1
  174. package/lib/partialLengths.js +160 -111
  175. package/lib/partialLengths.js.map +1 -1
  176. package/lib/perspective.d.ts +8 -27
  177. package/lib/perspective.d.ts.map +1 -1
  178. package/lib/perspective.js +8 -68
  179. package/lib/perspective.js.map +1 -1
  180. package/lib/revertibles.d.ts.map +1 -1
  181. package/lib/revertibles.js +2 -2
  182. package/lib/revertibles.js.map +1 -1
  183. package/lib/segmentInfos.d.ts +20 -106
  184. package/lib/segmentInfos.d.ts.map +1 -1
  185. package/lib/segmentInfos.js +26 -37
  186. package/lib/segmentInfos.js.map +1 -1
  187. package/lib/segmentPropertiesManager.d.ts +1 -14
  188. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  189. package/lib/segmentPropertiesManager.js +2 -16
  190. package/lib/segmentPropertiesManager.js.map +1 -1
  191. package/lib/snapshotLoader.d.ts.map +1 -1
  192. package/lib/snapshotLoader.js +39 -19
  193. package/lib/snapshotLoader.js.map +1 -1
  194. package/lib/snapshotV1.d.ts.map +1 -1
  195. package/lib/snapshotV1.js +34 -26
  196. package/lib/snapshotV1.js.map +1 -1
  197. package/lib/snapshotlegacy.d.ts.map +1 -1
  198. package/lib/snapshotlegacy.js +7 -10
  199. package/lib/snapshotlegacy.js.map +1 -1
  200. package/lib/stamps.d.ts +1 -1
  201. package/lib/stamps.js +1 -1
  202. package/lib/stamps.js.map +1 -1
  203. package/lib/test/Insertion.perf.spec.js +6 -51
  204. package/lib/test/Insertion.perf.spec.js.map +1 -1
  205. package/lib/test/PartialLengths.perf.spec.js +18 -25
  206. package/lib/test/PartialLengths.perf.spec.js.map +1 -1
  207. package/lib/test/Removal.perf.spec.js +13 -41
  208. package/lib/test/Removal.perf.spec.js.map +1 -1
  209. package/lib/test/beastTest.spec.d.ts.map +1 -1
  210. package/lib/test/beastTest.spec.js +42 -67
  211. package/lib/test/beastTest.spec.js.map +1 -1
  212. package/lib/test/client.annotateMarker.spec.js +1 -11
  213. package/lib/test/client.annotateMarker.spec.js.map +1 -1
  214. package/lib/test/client.applyMsg.spec.js +14 -14
  215. package/lib/test/client.applyMsg.spec.js.map +1 -1
  216. package/lib/test/client.getPosition.spec.js +1 -1
  217. package/lib/test/client.getPosition.spec.js.map +1 -1
  218. package/lib/test/client.localReference.spec.js +1 -1
  219. package/lib/test/client.localReference.spec.js.map +1 -1
  220. package/lib/test/client.rollback.spec.js +50 -59
  221. package/lib/test/client.rollback.spec.js.map +1 -1
  222. package/lib/test/client.rollbackFarm.spec.js +1 -1
  223. package/lib/test/client.rollbackFarm.spec.js.map +1 -1
  224. package/lib/test/client.searchForMarker.spec.js +4 -21
  225. package/lib/test/client.searchForMarker.spec.js.map +1 -1
  226. package/lib/test/index.d.ts +2 -2
  227. package/lib/test/index.d.ts.map +1 -1
  228. package/lib/test/index.js +1 -1
  229. package/lib/test/index.js.map +1 -1
  230. package/lib/test/mergeTree.annotate.deltaCallback.spec.js +15 -60
  231. package/lib/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
  232. package/lib/test/mergeTree.annotate.spec.js +48 -64
  233. package/lib/test/mergeTree.annotate.spec.js.map +1 -1
  234. package/lib/test/mergeTree.insert.deltaCallback.spec.js +10 -63
  235. package/lib/test/mergeTree.insert.deltaCallback.spec.js.map +1 -1
  236. package/lib/test/mergeTree.insertingWalk.spec.js +61 -127
  237. package/lib/test/mergeTree.insertingWalk.spec.js.map +1 -1
  238. package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +13 -94
  239. package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
  240. package/lib/test/mergeTree.markRangeRemoved.spec.js +10 -7
  241. package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  242. package/lib/test/mergeTree.walk.spec.js +2 -14
  243. package/lib/test/mergeTree.walk.spec.js.map +1 -1
  244. package/lib/test/mergeTreeOperationRunner.js +3 -3
  245. package/lib/test/mergeTreeOperationRunner.js.map +1 -1
  246. package/lib/test/obliterate.concurrent.spec.js +18 -23
  247. package/lib/test/obliterate.concurrent.spec.js.map +1 -1
  248. package/lib/test/obliterate.partialLength.spec.js +167 -137
  249. package/lib/test/obliterate.partialLength.spec.js.map +1 -1
  250. package/lib/test/obliterate.spec.js +17 -127
  251. package/lib/test/obliterate.spec.js.map +1 -1
  252. package/lib/test/partialLength.spec.js +29 -197
  253. package/lib/test/partialLength.spec.js.map +1 -1
  254. package/lib/test/perspective.spec.js +34 -0
  255. package/lib/test/perspective.spec.js.map +1 -1
  256. package/lib/test/propertyManager.spec.js +2 -2
  257. package/lib/test/propertyManager.spec.js.map +1 -1
  258. package/lib/test/resetPendingSegmentsToOp.spec.js +0 -2
  259. package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  260. package/lib/test/segmentGroupCollection.spec.js +10 -4
  261. package/lib/test/segmentGroupCollection.spec.js.map +1 -1
  262. package/lib/test/testClient.d.ts +1 -0
  263. package/lib/test/testClient.d.ts.map +1 -1
  264. package/lib/test/testClient.js +18 -28
  265. package/lib/test/testClient.js.map +1 -1
  266. package/lib/test/testClientLogger.d.ts.map +1 -1
  267. package/lib/test/testClientLogger.js +3 -10
  268. package/lib/test/testClientLogger.js.map +1 -1
  269. package/lib/test/testServer.d.ts +2 -1
  270. package/lib/test/testServer.d.ts.map +1 -1
  271. package/lib/test/testServer.js +7 -5
  272. package/lib/test/testServer.js.map +1 -1
  273. package/lib/test/testUtils.d.ts +36 -56
  274. package/lib/test/testUtils.d.ts.map +1 -1
  275. package/lib/test/testUtils.js +66 -48
  276. package/lib/test/testUtils.js.map +1 -1
  277. package/lib/test/text.d.ts +2 -2
  278. package/lib/test/text.d.ts.map +1 -1
  279. package/lib/test/text.js +6 -3
  280. package/lib/test/text.js.map +1 -1
  281. package/lib/textSegment.d.ts +0 -6
  282. package/lib/textSegment.d.ts.map +1 -1
  283. package/lib/textSegment.js.map +1 -1
  284. package/lib/tsdoc-metadata.json +1 -1
  285. package/lib/zamboni.d.ts.map +1 -1
  286. package/lib/zamboni.js +32 -28
  287. package/lib/zamboni.js.map +1 -1
  288. package/package.json +17 -20
  289. package/src/MergeTreeTextHelper.ts +17 -12
  290. package/src/client.ts +141 -197
  291. package/src/endOfTreeSegment.ts +11 -8
  292. package/src/index.ts +4 -3
  293. package/src/mergeTree.ts +482 -633
  294. package/src/mergeTreeDeltaCallback.ts +4 -8
  295. package/src/mergeTreeNodes.ts +66 -45
  296. package/src/partialLengths.ts +181 -137
  297. package/src/perspective.ts +17 -95
  298. package/src/revertibles.ts +2 -7
  299. package/src/segmentInfos.ts +48 -141
  300. package/src/segmentPropertiesManager.ts +2 -16
  301. package/src/snapshotLoader.ts +62 -30
  302. package/src/snapshotV1.ts +36 -28
  303. package/src/snapshotlegacy.ts +7 -16
  304. package/src/stamps.ts +1 -1
  305. package/src/textSegment.ts +0 -13
  306. package/src/zamboni.ts +38 -32
  307. package/tsconfig.json +1 -0
  308. package/prettier.config.cjs +0 -8
@@ -3,13 +3,37 @@
3
3
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
4
  * Licensed under the MIT License.
5
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || function (mod) {
23
+ if (mod && mod.__esModule) return mod;
24
+ var result = {};
25
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
26
+ __setModuleDefault(result, mod);
27
+ return result;
28
+ };
6
29
  Object.defineProperty(exports, "__esModule", { value: true });
7
30
  exports.verifyPartialLengths = exports.verifyExpectedPartialLengths = exports.PartialSequenceLengths = void 0;
8
31
  const internal_1 = require("@fluidframework/core-utils/internal");
9
- const constants_js_1 = require("./constants.js");
10
32
  const mergeTreeNodes_js_1 = require("./mergeTreeNodes.js");
33
+ const perspective_js_1 = require("./perspective.js");
11
34
  const segmentInfos_js_1 = require("./segmentInfos.js");
12
35
  const sortedSet_js_1 = require("./sortedSet.js");
36
+ const opstampUtils = __importStar(require("./stamps.js"));
13
37
  class PartialSequenceLengthsSet extends sortedSet_js_1.SortedSet {
14
38
  compare(a, b) {
15
39
  return a.seq - b.seq;
@@ -311,8 +335,8 @@ class PartialSequenceLengths {
311
335
  if (child.isLeaf()) {
312
336
  // Leaf segment
313
337
  const segment = child;
314
- if ((0, segmentInfos_js_1.wasMovedOnInsert)(segment)) {
315
- PartialSequenceLengths.accountForMoveOnInsert(combinedPartialLengths, segment, collabWindow);
338
+ if ((0, segmentInfos_js_1.wasRemovedOnInsert)(segment)) {
339
+ PartialSequenceLengths.accountForRemoveOnInsert(combinedPartialLengths, segment, collabWindow);
316
340
  }
317
341
  else {
318
342
  PartialSequenceLengths.accountForInsertion(combinedPartialLengths, segment, collabWindow);
@@ -324,22 +348,24 @@ class PartialSequenceLengths {
324
348
  return combinedPartialLengths;
325
349
  }
326
350
  /**
327
- * Assuming this segment was moved on insertion, inserts length information about that operation
351
+ * Assuming this segment was removed on insertion, inserts length information about that operation
328
352
  * into the appropriate per-client adjustments (the overall view needs no such adjustment since
329
353
  * from an observing client's perspective, the segment never exists).
330
354
  */
331
- static accountForMoveOnInsert(combinedPartialLengths, segment, collabWindow) {
355
+ static accountForRemoveOnInsert(combinedPartialLengths, segment, collabWindow) {
332
356
  (0, segmentInfos_js_1.assertInserted)(segment);
333
- const moveInfo = (0, segmentInfos_js_1.toMoveInfo)(segment);
334
- (0, internal_1.assert)(moveInfo !== undefined && (0, segmentInfos_js_1.wasMovedOnInsert)(segment), 0xab7 /* Segment was not moved on insert */);
335
- if (moveInfo.movedSeq <= collabWindow.minSeq) {
357
+ const removeInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
358
+ (0, internal_1.assert)(removeInfo !== undefined && (0, segmentInfos_js_1.wasRemovedOnInsert)(segment), 0xab7 /* Segment was not removed on insert */);
359
+ const firstRemove = removeInfo?.removes[0];
360
+ if (opstampUtils.lte(firstRemove, (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow))) {
336
361
  // This segment was obliterated as soon as it was inserted, and everyone was aware of the obliterate.
337
362
  // Thus every single client treats this segment as length 0 from every perspective, and no adjustments
338
363
  // are necessary.
339
364
  return;
340
365
  }
341
- const isLocal = segment.seq === constants_js_1.UnassignedSequenceNumber;
342
- const clientId = segment.clientId;
366
+ const { insert, cachedLength } = segment;
367
+ const isLocal = opstampUtils.isLocal(insert);
368
+ const { clientId } = insert;
343
369
  const partials = isLocal
344
370
  ? combinedPartialLengths.unsequencedRecords?.partialLengths
345
371
  : combinedPartialLengths.partialLengths;
@@ -349,33 +375,51 @@ class PartialSequenceLengths {
349
375
  }
350
376
  if (isLocal) {
351
377
  // Implication -> this is a local segment which will be obliterated as soon as it is acked.
352
- // For refSeqs preceding that movedSeq and localSeqs following the localSeq, it will be visible.
378
+ // For refSeqs preceding that removedSeq and localSeqs following the localSeq, it will be visible.
353
379
  // For the rest, it will not be visible.
354
380
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
355
- const localSeq = segment.localSeq;
381
+ const localSeq = insert.localSeq;
356
382
  partials.addOrUpdate({
357
383
  seq: localSeq,
358
384
  len: 0,
359
- seglen: segment.cachedLength,
385
+ seglen: cachedLength,
360
386
  clientId,
361
387
  });
362
388
  combinedPartialLengths.addLocalAdjustment({
363
- refSeq: moveInfo.movedSeq,
389
+ refSeq: firstRemove.seq,
364
390
  localSeq,
365
- seglen: -segment.cachedLength,
391
+ seglen: -cachedLength,
366
392
  });
393
+ const lastRemove = removeInfo.removes[removeInfo.removes.length - 1];
394
+ if (opstampUtils.isLocal(lastRemove)) {
395
+ // In addition to a remote sliceRemove causing this segment to be removed as soon as its insertion is acked,
396
+ // the local client has also removed it before its insertion was acked.
397
+ // It will therefore not be visible for a local reconnecting perspective beyond the removed localSeq.
398
+ partials.addOrUpdate({
399
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
400
+ seq: lastRemove.localSeq,
401
+ len: 0,
402
+ seglen: -cachedLength,
403
+ clientId,
404
+ });
405
+ combinedPartialLengths.addLocalAdjustment({
406
+ refSeq: firstRemove.seq,
407
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
408
+ localSeq: lastRemove.localSeq,
409
+ seglen: cachedLength,
410
+ });
411
+ }
367
412
  }
368
413
  else {
369
414
  // Segment was obliterated on insert. Generally this means it should be visible only to the
370
415
  // inserting client (in which case we add an adjustment to only that client's perspective),
371
416
  // but if that client has also removed it, we don't need to add anything.
372
- const removeInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
373
- const wasRemovedByInsertingClient = removeInfo !== undefined && removeInfo.removedClientIds.includes(clientId);
374
- const wasMovedByInsertingClient = moveInfo !== undefined && moveInfo.movedClientIds.includes(clientId);
375
- if (!wasRemovedByInsertingClient && !wasMovedByInsertingClient) {
376
- const moveSeq = moveInfo?.movedSeq;
377
- (0, internal_1.assert)(moveSeq !== undefined, 0xab8 /* ObliterateOnInsertion implies moveSeq is defined */);
378
- combinedPartialLengths.addClientAdjustment(clientId, moveSeq, segment.cachedLength);
417
+ const wasRemovedByInsertingClient = removeInfo !== undefined &&
418
+ removeInfo.removes.some((remove) => remove.clientId === clientId);
419
+ if (!wasRemovedByInsertingClient) {
420
+ const removeSeq = firstRemove?.seq;
421
+ (0, internal_1.assert)(removeSeq !== undefined, 0xab8 /* ObliterateOnInsertion implies removeSeq is defined */);
422
+ combinedPartialLengths.addClientAdjustment(clientId, removeSeq, cachedLength);
379
423
  }
380
424
  }
381
425
  }
@@ -385,15 +429,15 @@ class PartialSequenceLengths {
385
429
  */
386
430
  static accountForInsertion(combinedPartialLengths, segment, collabWindow) {
387
431
  (0, segmentInfos_js_1.assertInserted)(segment);
388
- if (segment.seq !== undefined && (0, mergeTreeNodes_js_1.seqLTE)(segment.seq, collabWindow.minSeq)) {
432
+ if (opstampUtils.lte(segment.insert, (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow))) {
389
433
  combinedPartialLengths.minLength += segment.cachedLength;
390
434
  return;
391
435
  }
392
- const isLocal = segment.seq === constants_js_1.UnassignedSequenceNumber;
436
+ const { insert, cachedLength: segmentLen } = segment;
437
+ const isLocal = opstampUtils.isLocal(insert);
393
438
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
394
- const seqOrLocalSeq = isLocal ? segment.localSeq : segment.seq;
395
- const segmentLen = segment.cachedLength;
396
- const clientId = segment.clientId;
439
+ const seqOrLocalSeq = isLocal ? insert.localSeq : insert.seq;
440
+ const clientId = insert.clientId;
397
441
  const partials = isLocal
398
442
  ? combinedPartialLengths.unsequencedRecords?.partialLengths
399
443
  : combinedPartialLengths.partialLengths;
@@ -426,55 +470,27 @@ class PartialSequenceLengths {
426
470
  static accountForRemoval(combinedPartialLengths, segment, collabWindow) {
427
471
  (0, segmentInfos_js_1.assertInserted)(segment);
428
472
  const removalInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
429
- const moveInfo = (0, segmentInfos_js_1.toMoveInfo)(segment);
430
- if (!removalInfo && !moveInfo) {
473
+ if (!removalInfo) {
431
474
  return;
432
475
  }
433
- if ((removalInfo?.removedSeq !== undefined &&
434
- (0, mergeTreeNodes_js_1.seqLTE)(removalInfo.removedSeq, collabWindow.minSeq)) ||
435
- (moveInfo?.movedSeq !== undefined && (0, mergeTreeNodes_js_1.seqLTE)(moveInfo.movedSeq, collabWindow.minSeq))) {
476
+ const firstRemove = removalInfo?.removes[0];
477
+ const minSeqStamp = (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow);
478
+ if (firstRemove !== undefined && opstampUtils.lte(firstRemove, minSeqStamp)) {
436
479
  combinedPartialLengths.minLength -= segment.cachedLength;
437
480
  return;
438
481
  }
439
- const removalIsLocal = !!removalInfo && removalInfo.removedSeq === constants_js_1.UnassignedSequenceNumber;
440
- const moveIsLocal = !!moveInfo && moveInfo.movedSeq === constants_js_1.UnassignedSequenceNumber;
441
- const isLocalInsertion = segment.seq === constants_js_1.UnassignedSequenceNumber;
442
- const isOnlyLocalRemoval = removalIsLocal && (!moveInfo || moveIsLocal);
443
- const isOnlyLocalMove = moveIsLocal && (!removalInfo || removalIsLocal);
444
- const isLocal = isLocalInsertion || isOnlyLocalRemoval || isOnlyLocalMove;
445
- if (segment.seq === constants_js_1.UnassignedSequenceNumber &&
446
- !(removalIsLocal && (!moveInfo || moveIsLocal)) &&
447
- !(moveIsLocal && (!removalInfo || removalIsLocal))) {
448
- throw new Error("Should have handled this codepath in wasMovedOnInsertion");
482
+ const removalIsLocal = !!firstRemove && opstampUtils.isLocal(firstRemove);
483
+ const isLocalInsertion = opstampUtils.isLocal(segment.insert);
484
+ const isOnlyLocalRemoval = removalIsLocal;
485
+ const isLocal = isLocalInsertion || isOnlyLocalRemoval;
486
+ if (isLocalInsertion && !removalIsLocal) {
487
+ throw new Error("Should have handled this codepath in wasRemovedOnInsertion");
449
488
  }
450
489
  const lenDelta = -segment.cachedLength;
451
- let clientId;
452
- let seqOrLocalSeq;
453
- // it's not possible to have an overlapping obliterate and remove that are both local
454
- (0, internal_1.assert)((!moveIsLocal && !removalIsLocal) || moveIsLocal !== removalIsLocal, 0x870 /* overlapping local obliterate and remove */);
455
- const clientsWithRemoveOrObliterate = new Set([
456
- ...(removalInfo?.removedClientIds ?? []),
457
- ...(moveInfo?.movedClientIds ?? []),
458
- ]);
459
- const removeHappenedFirst = removalInfo &&
460
- (!moveInfo ||
461
- moveIsLocal ||
462
- (!removalIsLocal && moveInfo.movedSeq > removalInfo.removedSeq));
463
- if (removeHappenedFirst) {
464
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
465
- seqOrLocalSeq = removalIsLocal ? removalInfo.localRemovedSeq : removalInfo.removedSeq;
466
- // The client who performed the remove is always stored
467
- // in the first position of removalInfo.
468
- clientId = removalInfo.removedClientIds[0];
469
- }
470
- else {
471
- (0, internal_1.assert)(moveInfo !== undefined, 0xab9 /* Expected move to exist if remove either did not exist or didn't happen first */);
472
- // The client who performed the move is always stored
473
- // in the first position of moveInfo.
474
- clientId = moveInfo.movedClientIds[0];
475
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
476
- seqOrLocalSeq = moveIsLocal ? moveInfo.localMovedSeq : moveInfo.movedSeq;
477
- }
490
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
491
+ const seqOrLocalSeq = removalIsLocal ? firstRemove.localSeq : firstRemove.seq;
492
+ const clientId = firstRemove.clientId;
493
+ const clientsWithRemoveOrObliterate = new Set(removalInfo?.removes.map((stamp) => stamp.clientId));
478
494
  const partials = isLocal
479
495
  ? combinedPartialLengths.unsequencedRecords?.partialLengths
480
496
  : combinedPartialLengths.partialLengths;
@@ -483,15 +499,30 @@ class PartialSequenceLengths {
483
499
  return;
484
500
  }
485
501
  if (isLocal) {
486
- // The segment is either inserted only locally or removed/moved only locally.
502
+ // The segment is either inserted only locally or removed only locally.
487
503
  // We already accounted for the insertion in the accountForInsertion codepath.
488
- // Only thing left to do is account for the removal.
489
- partials.addOrUpdate({
490
- seq: seqOrLocalSeq,
491
- clientId,
492
- len: 0,
493
- seglen: lenDelta,
494
- });
504
+ // Only thing left to do is account for the removal in local partial lengths.
505
+ // One thing to be careful about is that the removal should only apply to perspectives that saw
506
+ // the segment's insertion in the first place.
507
+ // When the segment's insertion was common knowledge (at or below minSeq) or also by the local client,
508
+ // all possible perspectives will have seen it.
509
+ if (opstampUtils.lte(segment.insert, minSeqStamp) ||
510
+ collabWindow.clientId === segment.insert.clientId) {
511
+ partials.addOrUpdate({
512
+ seq: seqOrLocalSeq,
513
+ clientId,
514
+ len: 0,
515
+ seglen: lenDelta,
516
+ });
517
+ }
518
+ else {
519
+ // ... otherwise, it's only visible to reconnecting perspectives above the seq of the insert.
520
+ combinedPartialLengths.addLocalAdjustment({
521
+ localSeq: seqOrLocalSeq,
522
+ refSeq: segment.insert.seq,
523
+ seglen: lenDelta,
524
+ });
525
+ }
495
526
  }
496
527
  else {
497
528
  partials.addOrUpdate({
@@ -503,7 +534,7 @@ class PartialSequenceLengths {
503
534
  for (const id of clientsWithRemoveOrObliterate) {
504
535
  if (id === collabWindow.clientId) {
505
536
  // The local client also removed or obliterated this segment.
506
- const localSeq = moveInfo?.localMovedSeq ?? removalInfo?.localRemovedSeq;
537
+ const { localSeq } = removalInfo.removes[removalInfo.removes.length - 1];
507
538
  if (localSeq === undefined) {
508
539
  // Sure, the local client did it--but that change was already acked.
509
540
  // No need to account for it in the unsequenced records.
@@ -514,13 +545,50 @@ class PartialSequenceLengths {
514
545
  // Local partial but its computation isn't required.
515
546
  continue;
516
547
  }
517
- (0, internal_1.assert)(localSeq !== undefined, 0xaba /* Local client was in move/removed client ids but segment has no local seq for either */);
518
- unsequencedRecords.partialLengths.addOrUpdate({
519
- seq: localSeq,
520
- clientId: collabWindow.clientId,
521
- seglen: lenDelta,
522
- len: 0,
523
- });
548
+ (0, internal_1.assert)(localSeq !== undefined, 0xaba /* Local client was in removed client ids but segment has no local seq for either */);
549
+ // Here...
550
+ // - The segment was removed locally at `localSeq`
551
+ // - The segment was also removed remotely at `seqOrLocalSeq`
552
+ // - We're ensuring that partial lengths works for arbitrary `LocalReconnectingPerspective`s.
553
+ //
554
+ // Visualize an arbitrary local reconnecting perspective in 2d space, where the x-axis is `seq` and the y-axis is `localSeq`.
555
+ // The events that have occurred to this segment divide the space into up to 6 regions:
556
+ //
557
+ // (localSeq)
558
+ // | | |
559
+ // | 1 | 2 | 3
560
+ // local remove |-----------------------------
561
+ // | | |
562
+ // | 4 | 5 | 6
563
+ // |----------------------------- (seq)
564
+ // insert remove
565
+ // In all regions but region 5, the segment has length 0 (it was not inserted yet in regions 1 or 4, and removed locally and/or remotely
566
+ // in regions 2, 3, and 6).
567
+ // `accountForInsertion` already added a partial lengths adjustment of +segment.cachedLength for regions 2, 3, 5, and 6.
568
+ // Above in this function, we've added a partial lengths adjustment of -segment.cachedLength for regions 3 and 6.
569
+ //
570
+ // Note that in this picture:
571
+ // - Adding entries to `unsequencedRecords.partialLengths` is like adding adjustments that affect anything above a given Y value
572
+ // - Adding entries to `combinedPartialLengths.partialLengths` is like adding adjustments that affect anything above a given X value
573
+ // - Adding entries with `addLocalAdjustment` is like adding adjustments that affect anything above a given X *and* Y value
574
+ // The remainder this block adds the necessary adjustments to make the length appear 0 in region 2 as well, keeping in mind that
575
+ // region 1 may or may not exist depending on if the insertion is in the collab window.
576
+ if (opstampUtils.isAcked(segment.insert) &&
577
+ opstampUtils.greaterThan(segment.insert, minSeqStamp)) {
578
+ combinedPartialLengths.addLocalAdjustment({
579
+ refSeq: segment.insert.seq,
580
+ localSeq,
581
+ seglen: lenDelta,
582
+ });
583
+ }
584
+ else {
585
+ unsequencedRecords.partialLengths.addOrUpdate({
586
+ seq: localSeq,
587
+ clientId: collabWindow.clientId,
588
+ seglen: lenDelta,
589
+ len: 0,
590
+ });
591
+ }
524
592
  // Because we've included deltas which take effect when either of localSeq or refSeq are high enough,
525
593
  // we need to offset this with an adjustment that takes effect when both are high enough.
526
594
  combinedPartialLengths.addLocalAdjustment({
@@ -536,15 +604,16 @@ class PartialSequenceLengths {
536
604
  }
537
605
  else {
538
606
  // Note that all clients that have a remove or obliterate operation on this segment
539
- // use the seq of the winning move/obliterate in their per-client adjustments!
607
+ // use the seq of the winning obliterate in their per-client adjustments!
540
608
  combinedPartialLengths.addClientAdjustment(id, seqOrLocalSeq, lenDelta);
541
609
  // Also ensure that all these clients have seen the segment as inserted before being removed
542
- // This is technically not necessary for removes (we never ask for the length of this block with
610
+ // This is technically not necessary for setRemoves (we never ask for the length of this block with
543
611
  // respect to a refSeq which this entry would affect), but it's simpler to just add it here.
544
612
  // We already add this entry as part of the accountForInsertion codepath for the client that
545
613
  // actually did insert the segment, hence not doing so [again] here.
546
- if (segment.seq > collabWindow.minSeq && id !== segment.clientId) {
547
- combinedPartialLengths.addClientAdjustment(id, segment.seq, segment.cachedLength);
614
+ if (opstampUtils.greaterThan(segment.insert, minSeqStamp) &&
615
+ id !== segment.insert.clientId) {
616
+ combinedPartialLengths.addClientAdjustment(id, segment.insert.seq, segment.cachedLength);
548
617
  }
549
618
  }
550
619
  }
@@ -588,15 +657,14 @@ class PartialSequenceLengths {
588
657
  if (child.isLeaf()) {
589
658
  const segment = child;
590
659
  const removalInfo = (0, segmentInfos_js_1.toRemovalInfo)(segment);
591
- const moveInfo = (0, segmentInfos_js_1.toMoveInfo)(segment);
592
- if (seq === segment.seq) {
593
- // if this segment was moved on insert, its length should
660
+ const firstRemove = removalInfo?.removes[0];
661
+ if (seq === segment.insert.seq) {
662
+ // if this segment was removed on insert, its length should
594
663
  // only be visible to the inserting client
595
- if (segment.seq !== undefined &&
596
- moveInfo &&
597
- moveInfo.movedSeq < segment.seq &&
598
- (0, segmentInfos_js_1.wasMovedOnInsert)(segment)) {
599
- this.addClientAdjustment(clientId, moveInfo.movedSeq, segment.cachedLength);
664
+ if (segment.insert.seq !== undefined &&
665
+ firstRemove !== undefined &&
666
+ (0, segmentInfos_js_1.wasRemovedOnInsert)(segment)) {
667
+ this.addClientAdjustment(clientId, firstRemove.seq, segment.cachedLength);
600
668
  failIncrementalPropagation = true;
601
669
  }
602
670
  else {
@@ -604,13 +672,13 @@ class PartialSequenceLengths {
604
672
  this.addClientAdjustment(clientId, seq, segment.cachedLength);
605
673
  }
606
674
  }
607
- const earlierDeletion = Math.min(removalInfo?.removedSeq ?? Number.MAX_VALUE, moveInfo?.movedSeq ?? Number.MAX_VALUE);
608
- if (segment.seq !== constants_js_1.UnassignedSequenceNumber && seq === earlierDeletion) {
675
+ if (opstampUtils.isAcked(segment.insert) && seq === firstRemove?.seq) {
609
676
  seqSeglen -= segment.cachedLength;
610
677
  if (clientId !== collabWindow.clientId) {
611
678
  this.addClientAdjustment(clientId, seq, -segment.cachedLength);
612
- if (segment.seq > collabWindow.minSeq && segment.clientId !== clientId) {
613
- this.addClientAdjustment(clientId, segment.seq, segment.cachedLength);
679
+ if (opstampUtils.greaterThan(segment.insert, (0, mergeTreeNodes_js_1.getMinSeqStamp)(collabWindow)) &&
680
+ segment.insert.clientId !== clientId) {
681
+ this.addClientAdjustment(clientId, segment.insert.seq, segment.cachedLength);
614
682
  failIncrementalPropagation = true;
615
683
  }
616
684
  }
@@ -685,13 +753,12 @@ class PartialSequenceLengths {
685
753
  (0, internal_1.assert)(this.unsequencedRecords !== undefined, 0x39f /* Local getPartialLength invoked without computing local partials. */);
686
754
  const unsequencedPartialLengths = this.unsequencedRecords.partialLengths;
687
755
  // Local segments at or before localSeq should also be included
688
- const local = unsequencedPartialLengths.latestLeq(localSeq);
689
- if (local) {
690
- length += local.len;
691
- // Lastly, we must add in any additional adjustment due to double-counting removes and obliterations
692
- // removing local-only segments.
693
- length += this.computeOverallRefSeqAdjustment(refSeq, localSeq);
694
- }
756
+ length += unsequencedPartialLengths.latestLeq(localSeq)?.len ?? 0;
757
+ // Lastly, we must add in any additional adjustment that should only take effect when both
758
+ // refSeq AND localSeq are above some threshold. This accounts for things like double-counting
759
+ // local+remote removes, or only subtracting the length out of a local remove if we've also seen
760
+ // the insert of the segment it affects. (see addLocalAdjustment usages for examples)
761
+ length += this.computeOverallRefSeqAdjustment(refSeq, localSeq);
695
762
  }
696
763
  return length;
697
764
  }
@@ -843,13 +910,18 @@ function verifyExpectedPartialLengths(mergeTree, node, refSeq, clientId, localSe
843
910
  const partialLen = node.partialLengths?.getPartialLength(refSeq, clientId, localSeq);
844
911
  let expected = 0;
845
912
  const nodesToVisit = [node];
913
+ const perspective = clientId === mergeTree.collabWindow.clientId
914
+ ? localSeq === undefined
915
+ ? new perspective_js_1.LocalDefaultPerspective(clientId)
916
+ : new perspective_js_1.LocalReconnectingPerspective(refSeq, clientId, localSeq)
917
+ : new perspective_js_1.PriorPerspective(refSeq, clientId);
846
918
  while (nodesToVisit.length > 0) {
847
919
  const thisNode = nodesToVisit.pop();
848
920
  if (!thisNode) {
849
921
  continue;
850
922
  }
851
923
  if (thisNode.isLeaf()) {
852
- expected += mergeTree["nodeLength"](thisNode, refSeq, clientId, localSeq) ?? 0;
924
+ expected += mergeTree["nodeLength"](thisNode, perspective) ?? 0;
853
925
  }
854
926
  else {
855
927
  nodesToVisit.push(...thisNode.children.slice(0, thisNode.childCount));