@fluidframework/sequence 2.32.0 → 2.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/api-report/sequence.legacy.alpha.api.md +39 -39
  3. package/dist/intervalCollection.d.ts +14 -9
  4. package/dist/intervalCollection.d.ts.map +1 -1
  5. package/dist/intervalCollection.js +137 -77
  6. package/dist/intervalCollection.js.map +1 -1
  7. package/dist/intervalCollectionMap.d.ts +5 -4
  8. package/dist/intervalCollectionMap.d.ts.map +1 -1
  9. package/dist/intervalCollectionMap.js +25 -50
  10. package/dist/intervalCollectionMap.js.map +1 -1
  11. package/dist/intervalCollectionMapInterfaces.d.ts +22 -15
  12. package/dist/intervalCollectionMapInterfaces.d.ts.map +1 -1
  13. package/dist/intervalCollectionMapInterfaces.js.map +1 -1
  14. package/dist/intervalIndex/intervalIndex.d.ts +1 -1
  15. package/dist/intervalIndex/intervalIndex.js.map +1 -1
  16. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +1 -1
  17. package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  18. package/dist/intervals/sequenceInterval.d.ts +3 -3
  19. package/dist/intervals/sequenceInterval.d.ts.map +1 -1
  20. package/dist/intervals/sequenceInterval.js +10 -9
  21. package/dist/intervals/sequenceInterval.js.map +1 -1
  22. package/dist/packageVersion.d.ts +1 -1
  23. package/dist/packageVersion.js +1 -1
  24. package/dist/packageVersion.js.map +1 -1
  25. package/dist/sequence.d.ts +4 -0
  26. package/dist/sequence.d.ts.map +1 -1
  27. package/dist/sequence.js +10 -0
  28. package/dist/sequence.js.map +1 -1
  29. package/dist/sharedIntervalCollection.d.ts +1 -1
  30. package/dist/sharedIntervalCollection.js.map +1 -1
  31. package/dist/sharedString.d.ts +0 -4
  32. package/dist/sharedString.d.ts.map +1 -1
  33. package/dist/sharedString.js +0 -11
  34. package/dist/sharedString.js.map +1 -1
  35. package/lib/intervalCollection.d.ts +14 -9
  36. package/lib/intervalCollection.d.ts.map +1 -1
  37. package/lib/intervalCollection.js +138 -78
  38. package/lib/intervalCollection.js.map +1 -1
  39. package/lib/intervalCollectionMap.d.ts +5 -4
  40. package/lib/intervalCollectionMap.d.ts.map +1 -1
  41. package/lib/intervalCollectionMap.js +26 -51
  42. package/lib/intervalCollectionMap.js.map +1 -1
  43. package/lib/intervalCollectionMapInterfaces.d.ts +22 -15
  44. package/lib/intervalCollectionMapInterfaces.d.ts.map +1 -1
  45. package/lib/intervalCollectionMapInterfaces.js.map +1 -1
  46. package/lib/intervalIndex/intervalIndex.d.ts +1 -1
  47. package/lib/intervalIndex/intervalIndex.js.map +1 -1
  48. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +1 -1
  49. package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  50. package/lib/intervals/sequenceInterval.d.ts +3 -3
  51. package/lib/intervals/sequenceInterval.d.ts.map +1 -1
  52. package/lib/intervals/sequenceInterval.js +10 -9
  53. package/lib/intervals/sequenceInterval.js.map +1 -1
  54. package/lib/packageVersion.d.ts +1 -1
  55. package/lib/packageVersion.js +1 -1
  56. package/lib/packageVersion.js.map +1 -1
  57. package/lib/sequence.d.ts +4 -0
  58. package/lib/sequence.d.ts.map +1 -1
  59. package/lib/sequence.js +10 -0
  60. package/lib/sequence.js.map +1 -1
  61. package/lib/sharedIntervalCollection.d.ts +1 -1
  62. package/lib/sharedIntervalCollection.js.map +1 -1
  63. package/lib/sharedString.d.ts +0 -4
  64. package/lib/sharedString.d.ts.map +1 -1
  65. package/lib/sharedString.js +0 -11
  66. package/lib/sharedString.js.map +1 -1
  67. package/lib/tsdoc-metadata.json +1 -1
  68. package/package.json +18 -20
  69. package/src/intervalCollection.ts +188 -96
  70. package/src/intervalCollectionMap.ts +31 -60
  71. package/src/intervalCollectionMapInterfaces.ts +34 -29
  72. package/src/intervalIndex/intervalIndex.ts +1 -1
  73. package/src/intervalIndex/overlappingIntervalsIndex.ts +1 -1
  74. package/src/intervals/sequenceInterval.ts +14 -2
  75. package/src/packageVersion.ts +1 -1
  76. package/src/sequence.ts +15 -0
  77. package/src/sharedIntervalCollection.ts +1 -1
  78. package/src/sharedString.ts +0 -11
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.intervalLocatorFromEndpoint = exports.IntervalCollection = exports.opsMap = exports.LocalIntervalCollection = exports.computeStickinessFromSide = exports.toOptionalSequencePlace = exports.toSequencePlace = exports.sidesFromStickiness = void 0;
7
+ exports.intervalLocatorFromEndpoint = exports.IntervalCollection = exports.LocalIntervalCollection = exports.computeStickinessFromSide = exports.toOptionalSequencePlace = exports.toSequencePlace = exports.sidesFromStickiness = void 0;
8
8
  /* eslint-disable no-bitwise */
9
9
  const client_utils_1 = require("@fluid-internal/client-utils");
10
10
  const internal_1 = require("@fluidframework/core-utils/internal");
@@ -116,7 +116,7 @@ class LocalIntervalCollection {
116
116
  this.removeIntervalFromIndexes(interval);
117
117
  this.removeIntervalListeners(interval);
118
118
  }
119
- addInterval(id, start, end, props, op) {
119
+ addInterval(id, start, end, props, op, rollback) {
120
120
  // This check is intended to prevent scenarios where a random interval is created and then
121
121
  // inserted into a collection. The aim is to ensure that the collection is created first
122
122
  // then the user can create/add intervals based on the collection
@@ -124,7 +124,7 @@ class LocalIntervalCollection {
124
124
  props[internal_2.reservedRangeLabelsKey][0] !== this.label) {
125
125
  throw new internal_3.LoggingError("Adding an interval that belongs to another interval collection is not permitted");
126
126
  }
127
- const interval = (0, index_js_2.createSequenceInterval)(this.label, id, start, end, this.client, index_js_2.IntervalType.SlideOnRemove, op, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint, props);
127
+ const interval = (0, index_js_2.createSequenceInterval)(this.label, id, start, end, this.client, index_js_2.IntervalType.SlideOnRemove, op, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint, props, rollback);
128
128
  this.add(interval);
129
129
  return interval;
130
130
  }
@@ -197,51 +197,6 @@ class LocalIntervalCollection {
197
197
  }
198
198
  }
199
199
  exports.LocalIntervalCollection = LocalIntervalCollection;
200
- const rebase = (collection, op, localOpMetadata) => {
201
- const { localSeq } = localOpMetadata;
202
- const rebasedValue = collection.rebaseLocalInterval(op.opName, op.value, localSeq);
203
- if (rebasedValue === undefined) {
204
- return undefined;
205
- }
206
- const rebasedOp = { ...op, value: rebasedValue };
207
- return { rebasedOp, rebasedLocalOpMetadata: localOpMetadata };
208
- };
209
- exports.opsMap = {
210
- [index_js_2.IntervalDeltaOpType.ADD]: {
211
- process: (collection, params, local, op, localOpMetadata) => {
212
- // if params is undefined, the interval was deleted during
213
- // rebasing
214
- if (!params) {
215
- return;
216
- }
217
- (0, internal_1.assert)(op !== undefined, 0x3fb /* op should exist here */);
218
- collection.ackAdd(params, local, op, localOpMetadata);
219
- },
220
- rebase,
221
- },
222
- [index_js_2.IntervalDeltaOpType.DELETE]: {
223
- process: (collection, params, local, op) => {
224
- (0, internal_1.assert)(op !== undefined, 0x3fc /* op should exist here */);
225
- collection.ackDelete(params, local, op);
226
- },
227
- rebase: (collection, op, localOpMetadata) => {
228
- // Deletion of intervals is based on id, so requires no rebasing.
229
- return { rebasedOp: op, rebasedLocalOpMetadata: localOpMetadata };
230
- },
231
- },
232
- [index_js_2.IntervalDeltaOpType.CHANGE]: {
233
- process: (collection, params, local, op, localOpMetadata) => {
234
- // if params is undefined, the interval was deleted during
235
- // rebasing
236
- if (!params) {
237
- return;
238
- }
239
- (0, internal_1.assert)(op !== undefined, 0x3fd /* op should exist here */);
240
- collection.ackChange(params, local, op, localOpMetadata);
241
- },
242
- rebase,
243
- },
244
- };
245
200
  class IntervalCollectionIterator {
246
201
  constructor(collection, iteratesForward = true, start, end) {
247
202
  this.results = [];
@@ -308,6 +263,112 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
308
263
  }
309
264
  return true;
310
265
  }
266
+ rollback(op, localOpMetadata) {
267
+ const { opName, value } = op;
268
+ const { id, properties } = (0, index_js_2.getSerializedProperties)(value);
269
+ const { localSeq, previous } = localOpMetadata;
270
+ switch (opName) {
271
+ case "add": {
272
+ const interval = this.getIntervalById(id);
273
+ if (interval) {
274
+ this.deleteExistingInterval({ interval, local: true, rollback: true });
275
+ }
276
+ break;
277
+ }
278
+ case "change": {
279
+ (0, internal_1.assert)(previous !== undefined, 0xb7c /* must have previous for change */);
280
+ const endpointsChanged = value.start !== undefined && value.end !== undefined;
281
+ const start = endpointsChanged
282
+ ? toOptionalSequencePlace(previous.start, previous.startSide)
283
+ : undefined;
284
+ const end = endpointsChanged
285
+ ? toOptionalSequencePlace(previous.end, previous.endSide)
286
+ : undefined;
287
+ this.change(id, {
288
+ start,
289
+ end,
290
+ props: Object.keys(properties).length > 0 ? properties : undefined,
291
+ rollback: true,
292
+ });
293
+ this.localSeqToSerializedInterval.delete(localSeq);
294
+ if (endpointsChanged) {
295
+ this.removePendingChange(value);
296
+ }
297
+ break;
298
+ }
299
+ case "delete": {
300
+ (0, internal_1.assert)(previous !== undefined, 0xb7d /* must have previous for delete */);
301
+ this.add({
302
+ id,
303
+ start: toSequencePlace(previous.start, previous.startSide),
304
+ end: toSequencePlace(previous.end, previous.endSide),
305
+ props: Object.keys(properties).length > 0 ? properties : undefined,
306
+ rollback: true,
307
+ });
308
+ break;
309
+ }
310
+ default:
311
+ (0, internal_1.unreachableCase)(opName);
312
+ }
313
+ }
314
+ process(op, local, message, localOpMetadata) {
315
+ const { opName, value } = op;
316
+ switch (opName) {
317
+ case "add": {
318
+ this.ackAdd(value, local, message, localOpMetadata);
319
+ break;
320
+ }
321
+ case "delete": {
322
+ this.ackDelete(value, local, message);
323
+ break;
324
+ }
325
+ case "change": {
326
+ this.ackChange(value, local, message, localOpMetadata);
327
+ break;
328
+ }
329
+ default:
330
+ (0, internal_1.unreachableCase)(opName);
331
+ }
332
+ }
333
+ resubmitMessage(op, localOpMetadata) {
334
+ const { opName, value } = op;
335
+ const { localSeq } = localOpMetadata;
336
+ const rebasedValue = opName === "delete" ? value : this.rebaseLocalInterval(opName, value, localSeq);
337
+ if (rebasedValue === undefined) {
338
+ return undefined;
339
+ }
340
+ this.submitDelta({ opName, value: rebasedValue }, localOpMetadata);
341
+ }
342
+ applyStashedOp(op) {
343
+ const { opName, value } = op;
344
+ const { id, properties } = (0, index_js_2.getSerializedProperties)(value);
345
+ switch (opName) {
346
+ case "add": {
347
+ this.add({
348
+ id,
349
+ // Todo: we should improve typing so we know add ops always have start and end
350
+ start: toSequencePlace(value.start, value.startSide),
351
+ end: toSequencePlace(value.end, value.endSide),
352
+ props: properties,
353
+ });
354
+ break;
355
+ }
356
+ case "change": {
357
+ this.change(id, {
358
+ start: toOptionalSequencePlace(value.start, value.startSide),
359
+ end: toOptionalSequencePlace(value.end, value.endSide),
360
+ props: properties,
361
+ });
362
+ break;
363
+ }
364
+ case "delete": {
365
+ this.removeIntervalById(id);
366
+ break;
367
+ }
368
+ default:
369
+ throw new Error("unknown ops should not be stashed");
370
+ }
371
+ }
311
372
  rebasePositionWithSegmentSlide(pos, seqNumberFrom, localSeq) {
312
373
  if (!this.client) {
313
374
  throw new internal_3.LoggingError("mergeTree client must exist");
@@ -417,7 +478,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
417
478
  /**
418
479
  * {@inheritdoc IIntervalCollection.add}
419
480
  */
420
- add({ id, start, end, props, }) {
481
+ add({ id, start, end, props, rollback, }) {
421
482
  if (!this.localCollection) {
422
483
  throw new internal_3.LoggingError("attach must be called prior to adding intervals");
423
484
  }
@@ -427,7 +488,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
427
488
  startSide !== undefined &&
428
489
  endSide !== undefined, 0x793 /* start and end cannot be undefined because they were not passed in as undefined */);
429
490
  this.assertStickinessEnabled(start, end);
430
- const interval = this.localCollection.addInterval(id ?? (0, uuid_1.v4)(), toSequencePlace(startPos, startSide), toSequencePlace(endPos, endSide), props);
491
+ const interval = this.localCollection.addInterval(id ?? (0, uuid_1.v4)(), toSequencePlace(startPos, startSide), toSequencePlace(endPos, endSide), props, undefined, rollback);
431
492
  if (interval) {
432
493
  if (!this.isCollaborating) {
433
494
  setSlideOnRemove(interval.start);
@@ -435,20 +496,20 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
435
496
  }
436
497
  const serializedInterval = interval.serialize();
437
498
  const localSeq = this.getNextLocalSeq();
438
- if (this.isCollaborating) {
499
+ if (this.isCollaborating && rollback !== true) {
439
500
  this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
501
+ this.submitDelta({
502
+ opName: "add",
503
+ value: serializedInterval,
504
+ }, {
505
+ localSeq,
506
+ });
440
507
  }
441
- this.submitDelta({
442
- opName: "add",
443
- value: serializedInterval,
444
- }, {
445
- localSeq,
446
- });
447
508
  }
448
509
  this.emit("addInterval", interval, true, undefined);
449
510
  return interval;
450
511
  }
451
- deleteExistingInterval(interval, local, op) {
512
+ deleteExistingInterval({ interval, local, op, rollback, }) {
452
513
  if (!this.localCollection) {
453
514
  throw new internal_3.LoggingError("Attach must be called before accessing intervals");
454
515
  }
@@ -456,12 +517,13 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
456
517
  this.localCollection.removeExistingInterval(interval);
457
518
  if (interval) {
458
519
  // Local ops get submitted to the server. Remote ops have the deserializer run.
459
- if (local) {
520
+ if (local && rollback !== true) {
460
521
  this.submitDelta({
461
522
  opName: "delete",
462
523
  value: interval.serialize(),
463
524
  }, {
464
525
  localSeq: this.getNextLocalSeq(),
526
+ previous: interval.serialize(),
465
527
  });
466
528
  }
467
529
  else {
@@ -481,14 +543,14 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
481
543
  }
482
544
  const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
483
545
  if (interval) {
484
- this.deleteExistingInterval(interval, true, undefined);
546
+ this.deleteExistingInterval({ interval, local: true });
485
547
  }
486
548
  return interval;
487
549
  }
488
550
  /**
489
551
  * {@inheritdoc IIntervalCollection.change}
490
552
  */
491
- change(id, { start, end, props }) {
553
+ change(id, { start, end, props, rollback, }) {
492
554
  if (!this.localCollection) {
493
555
  throw new internal_3.LoggingError("Attach must be called before accessing intervals");
494
556
  }
@@ -510,7 +572,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
510
572
  let deltaProps;
511
573
  let newInterval;
512
574
  if (props !== undefined) {
513
- deltaProps = interval.changeProperties(props);
575
+ deltaProps = interval.changeProperties(props, undefined, rollback);
514
576
  }
515
577
  const changeEndpoints = start !== undefined && end !== undefined;
516
578
  if (changeEndpoints) {
@@ -520,27 +582,25 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
520
582
  setSlideOnRemove(newInterval.end);
521
583
  }
522
584
  }
523
- // Emit a property bag containing the ID and the other (if any) properties changed
524
- const serializedInterval = (newInterval ?? interval).serializeDelta({
525
- props,
526
- includeEndpoints: changeEndpoints,
527
- });
528
- const localSeq = this.getNextLocalSeq();
529
- if (this.isCollaborating) {
585
+ if (this.isCollaborating && rollback !== true) {
586
+ // Emit a property bag containing the ID and the other (if any) properties changed
587
+ const serializedInterval = (newInterval ?? interval).serializeDelta({ props, includeEndpoints: changeEndpoints });
588
+ const localSeq = this.getNextLocalSeq();
530
589
  this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
590
+ this.addPendingChange(id, serializedInterval);
591
+ this.submitDelta({
592
+ opName: "change",
593
+ value: serializedInterval,
594
+ }, {
595
+ localSeq,
596
+ previous: interval.serialize(),
597
+ });
531
598
  }
532
- this.submitDelta({
533
- opName: "change",
534
- value: serializedInterval,
535
- }, {
536
- localSeq,
537
- });
538
599
  if (deltaProps !== undefined) {
539
600
  this.emit("propertyChanged", interval, deltaProps, true, undefined);
540
601
  this.emit("changed", newInterval ?? interval, deltaProps, newInterval ? interval : undefined, true, false);
541
602
  }
542
603
  if (newInterval) {
543
- this.addPendingChange(id, serializedInterval);
544
604
  this.emitChange(newInterval, interval, true, false);
545
605
  this.client?.removeLocalReferencePosition(interval.start);
546
606
  this.client?.removeLocalReferencePosition(interval.end);
@@ -836,7 +896,7 @@ class IntervalCollection extends client_utils_1.TypedEventEmitter {
836
896
  const { id } = (0, index_js_2.getSerializedProperties)(serializedInterval);
837
897
  const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
838
898
  if (interval) {
839
- this.deleteExistingInterval(interval, local, op);
899
+ this.deleteExistingInterval({ interval, local, op });
840
900
  }
841
901
  }
842
902
  serializeInternal(version) {