@fluidframework/sequence 0.59.4001 → 1.1.0-75972

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 (68) hide show
  1. package/.eslintrc.js +1 -1
  2. package/README.md +18 -6
  3. package/dist/defaultMap.d.ts +2 -6
  4. package/dist/defaultMap.d.ts.map +1 -1
  5. package/dist/defaultMap.js +27 -37
  6. package/dist/defaultMap.js.map +1 -1
  7. package/dist/defaultMapInterfaces.d.ts +24 -3
  8. package/dist/defaultMapInterfaces.d.ts.map +1 -1
  9. package/dist/defaultMapInterfaces.js.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/intervalCollection.d.ts +93 -8
  14. package/dist/intervalCollection.d.ts.map +1 -1
  15. package/dist/intervalCollection.js +434 -178
  16. package/dist/intervalCollection.js.map +1 -1
  17. package/dist/packageVersion.d.ts +1 -1
  18. package/dist/packageVersion.d.ts.map +1 -1
  19. package/dist/packageVersion.js +1 -1
  20. package/dist/packageVersion.js.map +1 -1
  21. package/dist/sequence.d.ts +6 -7
  22. package/dist/sequence.d.ts.map +1 -1
  23. package/dist/sequence.js +17 -21
  24. package/dist/sequence.js.map +1 -1
  25. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  26. package/dist/sharedIntervalCollection.js +2 -2
  27. package/dist/sharedIntervalCollection.js.map +1 -1
  28. package/dist/sharedSequence.js.map +1 -1
  29. package/dist/sparsematrix.js +2 -2
  30. package/dist/sparsematrix.js.map +1 -1
  31. package/lib/defaultMap.d.ts +2 -6
  32. package/lib/defaultMap.d.ts.map +1 -1
  33. package/lib/defaultMap.js +27 -37
  34. package/lib/defaultMap.js.map +1 -1
  35. package/lib/defaultMapInterfaces.d.ts +24 -3
  36. package/lib/defaultMapInterfaces.d.ts.map +1 -1
  37. package/lib/defaultMapInterfaces.js.map +1 -1
  38. package/lib/index.d.ts +2 -2
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js.map +1 -1
  41. package/lib/intervalCollection.d.ts +93 -8
  42. package/lib/intervalCollection.d.ts.map +1 -1
  43. package/lib/intervalCollection.js +435 -179
  44. package/lib/intervalCollection.js.map +1 -1
  45. package/lib/packageVersion.d.ts +1 -1
  46. package/lib/packageVersion.d.ts.map +1 -1
  47. package/lib/packageVersion.js +1 -1
  48. package/lib/packageVersion.js.map +1 -1
  49. package/lib/sequence.d.ts +6 -7
  50. package/lib/sequence.d.ts.map +1 -1
  51. package/lib/sequence.js +18 -22
  52. package/lib/sequence.js.map +1 -1
  53. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  54. package/lib/sharedIntervalCollection.js +2 -2
  55. package/lib/sharedIntervalCollection.js.map +1 -1
  56. package/lib/sharedSequence.js.map +1 -1
  57. package/lib/sparsematrix.js +2 -2
  58. package/lib/sparsematrix.js.map +1 -1
  59. package/package.json +23 -45
  60. package/src/defaultMap.ts +39 -41
  61. package/src/defaultMapInterfaces.ts +28 -3
  62. package/src/index.ts +3 -0
  63. package/src/intervalCollection.ts +575 -211
  64. package/src/packageVersion.ts +1 -1
  65. package/src/sequence.ts +36 -38
  66. package/src/sharedIntervalCollection.ts +4 -3
  67. package/src/sharedSequence.ts +1 -1
  68. package/src/sparsematrix.ts +2 -2
@@ -15,20 +15,61 @@ var __rest = (this && this.__rest) || function (s, e) {
15
15
  };
16
16
  /* eslint-disable no-bitwise */
17
17
  import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
18
- import { addProperties, createMap, IntervalTree, LocalReference, PropertiesManager, RedBlackTree, ReferenceType, reservedRangeLabelsKey, UnassignedSequenceNumber, } from "@fluidframework/merge-tree";
18
+ import { UsageError } from "@fluidframework/container-utils";
19
+ import { addProperties, createMap, IntervalTree, LocalReference, MergeTreeDeltaType, PropertiesManager, RedBlackTree, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, } from "@fluidframework/merge-tree";
20
+ import { LoggingError } from "@fluidframework/telemetry-utils";
19
21
  import { v4 as uuid } from "uuid";
20
22
  const reservedIntervalIdKey = "intervalId";
21
23
  export var IntervalType;
22
24
  (function (IntervalType) {
23
25
  IntervalType[IntervalType["Simple"] = 0] = "Simple";
24
26
  IntervalType[IntervalType["Nest"] = 1] = "Nest";
27
+ /**
28
+ * SlideOnRemove indicates that the ends of the interval will slide if the segment
29
+ * they reference is removed and acked.
30
+ * See `packages\dds\merge-tree\REFERENCEPOSITIONS.md` for details
31
+ * SlideOnRemove is the default interval behavior and does not need to be specified.
32
+ */
25
33
  IntervalType[IntervalType["SlideOnRemove"] = 2] = "SlideOnRemove";
34
+ /**
35
+ * @internal
36
+ * A temporary interval, used internally
37
+ */
26
38
  IntervalType[IntervalType["Transient"] = 4] = "Transient";
27
39
  })(IntervalType || (IntervalType = {}));
40
+ /**
41
+ * Decompress an interval after loading a summary from JSON. The exact format
42
+ * of this compression is unspecified and subject to change
43
+ */
44
+ function decompressInterval(interval, label) {
45
+ return {
46
+ start: interval[0],
47
+ end: interval[1],
48
+ sequenceNumber: interval[2],
49
+ intervalType: interval[3],
50
+ properties: Object.assign(Object.assign({}, interval[4]), { [reservedRangeLabelsKey]: label }),
51
+ };
52
+ }
53
+ /**
54
+ * Compress an interval prior to serialization as JSON. The exact format of this
55
+ * compression is unspecified and subject to change
56
+ */
57
+ function compressInterval(interval) {
58
+ const { start, end, sequenceNumber, intervalType, properties } = interval;
59
+ return [
60
+ start,
61
+ end,
62
+ sequenceNumber,
63
+ intervalType,
64
+ Object.assign(Object.assign({}, properties), { [reservedRangeLabelsKey]: undefined }),
65
+ ];
66
+ }
28
67
  export class Interval {
29
68
  constructor(start, end, props) {
30
69
  this.start = start;
31
70
  this.end = end;
71
+ this.propertyManager = new PropertiesManager();
72
+ this.properties = {};
32
73
  if (props) {
33
74
  this.addProperties(props);
34
75
  }
@@ -111,12 +152,7 @@ export class Interval {
111
152
  }
112
153
  addProperties(newProps, collaborating = false, seq, op) {
113
154
  if (newProps) {
114
- if (!this.propertyManager) {
115
- this.propertyManager = new PropertiesManager();
116
- }
117
- if (!this.properties) {
118
- this.properties = createMap();
119
- }
155
+ this.initializeProperties();
120
156
  return this.propertyManager.addProperties(this.properties, newProps, op, seq, collaborating);
121
157
  }
122
158
  }
@@ -127,7 +163,20 @@ export class Interval {
127
163
  // Return undefined to indicate that no change is necessary.
128
164
  return;
129
165
  }
130
- return new Interval(startPos, endPos, this.properties);
166
+ const newInterval = new Interval(startPos, endPos);
167
+ if (this.properties) {
168
+ newInterval.initializeProperties();
169
+ this.propertyManager.copyTo(this.properties, newInterval.properties, newInterval.propertyManager);
170
+ }
171
+ return newInterval;
172
+ }
173
+ initializeProperties() {
174
+ if (!this.propertyManager) {
175
+ this.propertyManager = new PropertiesManager();
176
+ }
177
+ if (!this.properties) {
178
+ this.properties = createMap();
179
+ }
131
180
  }
132
181
  }
133
182
  export class SequenceInterval {
@@ -135,10 +184,41 @@ export class SequenceInterval {
135
184
  this.start = start;
136
185
  this.end = end;
137
186
  this.intervalType = intervalType;
187
+ this.propertyManager = new PropertiesManager();
188
+ this.properties = {};
138
189
  if (props) {
139
190
  this.addProperties(props);
140
191
  }
141
192
  }
193
+ /**
194
+ * @internal
195
+ * Subscribes to position change events on this interval if there are no current listeners.
196
+ */
197
+ addPositionChangeListeners(beforePositionChange, afterPositionChange) {
198
+ var _a, _b;
199
+ var _c, _d;
200
+ if (this.callbacks === undefined) {
201
+ this.callbacks = {
202
+ beforePositionChange,
203
+ afterPositionChange,
204
+ };
205
+ const startCbs = (_a = (_c = this.start).callbacks) !== null && _a !== void 0 ? _a : (_c.callbacks = {});
206
+ const endCbs = (_b = (_d = this.end).callbacks) !== null && _b !== void 0 ? _b : (_d.callbacks = {});
207
+ startCbs.beforeSlide = endCbs.beforeSlide = beforePositionChange;
208
+ startCbs.afterSlide = endCbs.afterSlide = afterPositionChange;
209
+ }
210
+ }
211
+ /**
212
+ * @internal
213
+ * Removes the currently subscribed position change listeners.
214
+ */
215
+ removePositionChangeListeners() {
216
+ if (this.callbacks) {
217
+ this.callbacks = undefined;
218
+ this.start.callbacks = undefined;
219
+ this.end.callbacks = undefined;
220
+ }
221
+ }
142
222
  serialize(client) {
143
223
  const startPosition = this.start.toPosition();
144
224
  const endPosition = this.end.toPosition();
@@ -202,12 +282,7 @@ export class SequenceInterval {
202
282
  return new SequenceInterval(this.start.min(b.start), this.end.max(b.end), this.intervalType);
203
283
  }
204
284
  addProperties(newProps, collab = false, seq, op) {
205
- if (!this.propertyManager) {
206
- this.propertyManager = new PropertiesManager();
207
- }
208
- if (!this.properties) {
209
- this.properties = createMap();
210
- }
285
+ this.initializeProperties();
211
286
  return this.propertyManager.addProperties(this.properties, newProps, op, seq, collab);
212
287
  }
213
288
  overlapsPos(bstart, bend) {
@@ -216,59 +291,102 @@ export class SequenceInterval {
216
291
  return (endPos > bstart) && (startPos < bend);
217
292
  }
218
293
  modify(label, start, end, op) {
219
- const startPos = start !== null && start !== void 0 ? start : this.start.toPosition();
220
- const endPos = end !== null && end !== void 0 ? end : this.end.toPosition();
221
- if (this.start.toPosition() === startPos && this.end.toPosition() === endPos) {
222
- // Return undefined to indicate that no change is necessary.
223
- return;
224
- }
225
- const newInterval = createSequenceInterval(label, startPos, endPos, this.start.getClient(), this.intervalType, op);
294
+ const getRefType = (baseType) => {
295
+ let refType = baseType;
296
+ if (op === undefined) {
297
+ refType &= ~ReferenceType.SlideOnRemove;
298
+ refType |= ReferenceType.StayOnRemove;
299
+ }
300
+ return refType;
301
+ };
302
+ let startRef = this.start;
303
+ if (start !== undefined) {
304
+ startRef = createPositionReference(this.start.getClient(), start, getRefType(this.start.refType), op);
305
+ startRef.addProperties(this.start.properties);
306
+ }
307
+ let endRef = this.end;
308
+ if (end !== undefined) {
309
+ endRef = createPositionReference(this.end.getClient(), end, getRefType(this.end.refType), op);
310
+ endRef.addProperties(this.end.properties);
311
+ }
312
+ startRef.pairedRef = endRef;
313
+ endRef.pairedRef = startRef;
314
+ const newInterval = new SequenceInterval(startRef, endRef, this.intervalType);
226
315
  if (this.properties) {
227
- newInterval.addProperties(this.properties);
316
+ newInterval.initializeProperties();
317
+ this.propertyManager.copyTo(this.properties, newInterval.properties, newInterval.propertyManager);
228
318
  }
229
319
  return newInterval;
230
320
  }
321
+ initializeProperties() {
322
+ if (!this.propertyManager) {
323
+ this.propertyManager = new PropertiesManager();
324
+ }
325
+ if (!this.properties) {
326
+ this.properties = createMap();
327
+ }
328
+ }
231
329
  }
232
- function createPositionReference(client, pos, refType, op) {
233
- const segoff = client.getContainingSegment(pos, op);
234
- if (segoff === null || segoff === void 0 ? void 0 : segoff.segment) {
235
- const lref = new LocalReference(client, segoff.segment, segoff.offset, refType);
236
- if (refType !== ReferenceType.Transient) {
237
- client.addLocalReference(lref);
330
+ function createPositionReferenceFromSegoff(client, segoff, refType, op) {
331
+ if (segoff.segment) {
332
+ const ref = client.createLocalReferencePosition(segoff.segment, segoff.offset, refType, undefined);
333
+ return ref;
334
+ }
335
+ else {
336
+ if (!op && !refTypeIncludesFlag(refType, ReferenceType.Transient)) {
337
+ throw new UsageError("Non-transient references need segment");
238
338
  }
239
- return lref;
339
+ return new LocalReference(client, undefined, 0, refType);
340
+ }
341
+ }
342
+ function createPositionReference(client, pos, refType, op) {
343
+ let segoff;
344
+ if (op) {
345
+ assert((refType & ReferenceType.SlideOnRemove) !== 0, 0x2f5 /* op create references must be SlideOnRemove */);
346
+ segoff = client.getContainingSegment(pos, op);
347
+ segoff = client.getSlideToSegment(segoff);
348
+ }
349
+ else {
350
+ assert((refType & ReferenceType.SlideOnRemove) === 0, 0x2f6 /* SlideOnRemove references must be op created */);
351
+ segoff = client.getContainingSegment(pos);
240
352
  }
241
- return new LocalReference(client, undefined);
353
+ return createPositionReferenceFromSegoff(client, segoff, refType, op);
242
354
  }
243
355
  function createSequenceInterval(label, start, end, client, intervalType, op) {
244
356
  let beginRefType = ReferenceType.RangeBegin;
245
357
  let endRefType = ReferenceType.RangeEnd;
246
- if (intervalType === IntervalType.Nest) {
247
- beginRefType = ReferenceType.NestBegin;
248
- endRefType = ReferenceType.NestEnd;
249
- }
250
- else if (intervalType === IntervalType.Transient) {
358
+ if (intervalType === IntervalType.Transient) {
251
359
  beginRefType = ReferenceType.Transient;
252
360
  endRefType = ReferenceType.Transient;
253
361
  }
254
- // TODO: Should SlideOnRemove be the default behavior?
255
- if (intervalType & IntervalType.SlideOnRemove) {
256
- beginRefType |= ReferenceType.SlideOnRemove;
257
- endRefType |= ReferenceType.SlideOnRemove;
362
+ else {
363
+ if (intervalType === IntervalType.Nest) {
364
+ beginRefType = ReferenceType.NestBegin;
365
+ endRefType = ReferenceType.NestEnd;
366
+ }
367
+ // All non-transient interval references must eventually be SlideOnRemove
368
+ // To ensure eventual consistency, they must start as StayOnRemove when
369
+ // pending (created locally and creation op is not acked)
370
+ if (op) {
371
+ beginRefType |= ReferenceType.SlideOnRemove;
372
+ endRefType |= ReferenceType.SlideOnRemove;
373
+ }
374
+ else {
375
+ beginRefType |= ReferenceType.StayOnRemove;
376
+ endRefType |= ReferenceType.StayOnRemove;
377
+ }
258
378
  }
259
379
  const startLref = createPositionReference(client, start, beginRefType, op);
260
380
  const endLref = createPositionReference(client, end, endRefType, op);
261
- if (startLref && endLref) {
262
- startLref.pairedRef = endLref;
263
- endLref.pairedRef = startLref;
264
- const rangeProp = {
265
- [reservedRangeLabelsKey]: [label],
266
- };
267
- startLref.addProperties(rangeProp);
268
- endLref.addProperties(rangeProp);
269
- const ival = new SequenceInterval(startLref, endLref, intervalType, rangeProp);
270
- return ival;
271
- }
381
+ startLref.pairedRef = endLref;
382
+ endLref.pairedRef = startLref;
383
+ const rangeProp = {
384
+ [reservedRangeLabelsKey]: [label],
385
+ };
386
+ startLref.addProperties(rangeProp);
387
+ endLref.addProperties(rangeProp);
388
+ const ival = new SequenceInterval(startLref, endLref, intervalType, rangeProp);
389
+ return ival;
272
390
  }
273
391
  export function defaultIntervalConflictResolver(a, b) {
274
392
  a.addPropertySet(b.properties);
@@ -289,11 +407,15 @@ export function createIntervalIndex(conflict) {
289
407
  return lc;
290
408
  }
291
409
  export class LocalIntervalCollection {
292
- constructor(client, label, helpers) {
410
+ constructor(client, label, helpers,
411
+ /** Callback invoked each time one of the endpoints of an interval slides. */
412
+ onPositionChange) {
293
413
  this.client = client;
294
414
  this.label = label;
295
415
  this.helpers = helpers;
416
+ this.onPositionChange = onPositionChange;
296
417
  this.intervalTree = new IntervalTree();
418
+ this.intervalIdMap = new Map();
297
419
  // eslint-disable-next-line @typescript-eslint/unbound-method
298
420
  this.endIntervalTree = new RedBlackTree(helpers.compareEnds);
299
421
  }
@@ -301,7 +423,7 @@ export class LocalIntervalCollection {
301
423
  this.conflictResolver = conflictResolver;
302
424
  this.endConflictResolver =
303
425
  (key, currentKey) => {
304
- const ival = this.conflictResolver(key, currentKey);
426
+ const ival = conflictResolver(key, currentKey);
305
427
  return {
306
428
  data: ival,
307
429
  key: ival,
@@ -316,13 +438,22 @@ export class LocalIntervalCollection {
316
438
  // without ID's.
317
439
  return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
318
440
  }
441
+ /**
442
+ * Validates that a serialized interval has the ID property. Creates an ID
443
+ * if one does not already exist
444
+ *
445
+ * @param serializedInterval - The interval to be checked
446
+ * @returns The interval's existing or newly created id
447
+ */
319
448
  ensureSerializedId(serializedInterval) {
320
449
  var _a;
321
- if (((_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey]) === undefined) {
450
+ let id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
451
+ if (id === undefined) {
322
452
  // An interval came over the wire without an ID, so create a non-unique one based on start/end.
323
453
  // This will allow all clients to refer to this interval consistently.
454
+ id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
324
455
  const newProps = {
325
- [reservedIntervalIdKey]: this.createLegacyId(serializedInterval.start, serializedInterval.end),
456
+ [reservedIntervalIdKey]: id,
326
457
  };
327
458
  serializedInterval.properties = addProperties(serializedInterval.properties, newProps);
328
459
  }
@@ -332,6 +463,7 @@ export class LocalIntervalCollection {
332
463
  enumerable: true,
333
464
  writable: false,
334
465
  });
466
+ return id;
335
467
  }
336
468
  mapUntil(fn) {
337
469
  this.intervalTree.mapUntil(fn);
@@ -398,14 +530,12 @@ export class LocalIntervalCollection {
398
530
  }
399
531
  }
400
532
  findOverlappingIntervals(startPosition, endPosition) {
401
- if (!this.intervalTree.intervals.isEmpty()) {
402
- const transientInterval = this.helpers.create("transient", startPosition, endPosition, this.client, IntervalType.Transient);
403
- const overlappingIntervalNodes = this.intervalTree.match(transientInterval);
404
- return overlappingIntervalNodes.map((node) => node.key);
405
- }
406
- else {
533
+ if (endPosition < startPosition || this.intervalTree.intervals.isEmpty()) {
407
534
  return [];
408
535
  }
536
+ const transientInterval = this.helpers.create("transient", startPosition, endPosition, this.client, IntervalType.Transient);
537
+ const overlappingIntervalNodes = this.intervalTree.match(transientInterval);
538
+ return overlappingIntervalNodes.map((node) => node.key);
409
539
  }
410
540
  previousInterval(pos) {
411
541
  const transientInterval = this.helpers.create("transient", pos, pos, this.client, IntervalType.Transient);
@@ -427,9 +557,16 @@ export class LocalIntervalCollection {
427
557
  this.endIntervalTree.remove(transientInterval);
428
558
  return transientInterval;
429
559
  }
430
- removeExistingInterval(interval) {
560
+ removeIntervalFromIndex(interval) {
431
561
  this.intervalTree.removeExisting(interval);
432
562
  this.endIntervalTree.remove(interval);
563
+ const id = interval.getIntervalId();
564
+ assert(id !== undefined, 0x311 /* expected id to exist on interval */);
565
+ this.intervalIdMap.delete(id);
566
+ }
567
+ removeExistingInterval(interval) {
568
+ this.removeIntervalFromIndex(interval);
569
+ this.removeIntervalListeners(interval);
433
570
  }
434
571
  createInterval(start, end, intervalType, op) {
435
572
  return this.helpers.create(this.label, start, end, this.client, intervalType, op);
@@ -451,8 +588,9 @@ export class LocalIntervalCollection {
451
588
  }
452
589
  return interval;
453
590
  }
454
- add(interval) {
455
- assert(Object.prototype.hasOwnProperty.call(interval.properties, reservedIntervalIdKey), 0x2c0 /* "ID must be created before adding interval to collection" */);
591
+ addIntervalToIndex(interval) {
592
+ const id = interval.getIntervalId();
593
+ assert(id !== undefined, 0x2c0 /* "ID must be created before adding interval to collection" */);
456
594
  // Make the ID immutable.
457
595
  Object.defineProperty(interval.properties, reservedIntervalIdKey, {
458
596
  configurable: false,
@@ -461,17 +599,14 @@ export class LocalIntervalCollection {
461
599
  });
462
600
  this.intervalTree.put(interval, this.conflictResolver);
463
601
  this.endIntervalTree.put(interval, interval, this.endConflictResolver);
602
+ this.intervalIdMap.set(id, interval);
603
+ }
604
+ add(interval) {
605
+ this.addIntervalToIndex(interval);
606
+ this.addIntervalListeners(interval);
464
607
  }
465
608
  getIntervalById(id) {
466
- let result;
467
- this.mapUntil((interval) => {
468
- if (interval.getIntervalId() === id) {
469
- result = interval;
470
- return false;
471
- }
472
- return true;
473
- });
474
- return result;
609
+ return this.intervalIdMap.get(id);
475
610
  }
476
611
  changeInterval(interval, start, end, op) {
477
612
  const newInterval = interval.modify(this.label, start, end, op);
@@ -484,7 +619,25 @@ export class LocalIntervalCollection {
484
619
  serialize() {
485
620
  const client = this.client;
486
621
  const intervals = this.intervalTree.intervals.keys();
487
- return intervals.map((interval) => interval.serialize(client));
622
+ return {
623
+ label: this.label,
624
+ intervals: intervals.map((interval) => compressInterval(interval.serialize(client))),
625
+ version: 2,
626
+ };
627
+ }
628
+ addIntervalListeners(interval) {
629
+ if (interval instanceof SequenceInterval) {
630
+ interval.addPositionChangeListeners(() => this.removeIntervalFromIndex(interval), () => {
631
+ var _a;
632
+ this.addIntervalToIndex(interval);
633
+ (_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval);
634
+ });
635
+ }
636
+ }
637
+ removeIntervalListeners(interval) {
638
+ if (interval instanceof SequenceInterval) {
639
+ interval.removePositionChangeListeners();
640
+ }
488
641
  }
489
642
  }
490
643
  LocalIntervalCollection.legacyIdPrefix = "legacy";
@@ -514,37 +667,12 @@ export class SequenceIntervalCollectionValueType {
514
667
  }
515
668
  SequenceIntervalCollectionValueType.Name = "sharedStringIntervalCollection";
516
669
  SequenceIntervalCollectionValueType._factory = new SequenceIntervalCollectionFactory();
517
- SequenceIntervalCollectionValueType._ops = new Map([[
518
- "add",
519
- {
520
- process: (value, params, local, op) => {
521
- value.ackAdd(params, local, op);
522
- },
523
- },
524
- ],
525
- [
526
- "delete",
527
- {
528
- process: (value, params, local, op) => {
529
- value.ackDelete(params, local, op);
530
- },
531
- },
532
- ],
533
- [
534
- "change",
535
- {
536
- process: (value, params, local, op) => {
537
- value.ackChange(params, local, op);
538
- },
539
- },
540
- ]]);
670
+ SequenceIntervalCollectionValueType._ops = makeOpsMap();
541
671
  const compareIntervalEnds = (a, b) => a.end - b.end;
542
672
  function createInterval(label, start, end, client) {
543
- let rangeProp;
544
- if (label && (label.length > 0)) {
545
- rangeProp = {
546
- [reservedRangeLabelsKey]: [label],
547
- };
673
+ const rangeProp = {};
674
+ if (label && label.length > 0) {
675
+ rangeProp[reservedRangeLabelsKey] = [label];
548
676
  }
549
677
  return new Interval(start, end, rangeProp);
550
678
  }
@@ -575,30 +703,45 @@ export class IntervalCollectionValueType {
575
703
  }
576
704
  IntervalCollectionValueType.Name = "sharedIntervalCollection";
577
705
  IntervalCollectionValueType._factory = new IntervalCollectionFactory();
578
- IntervalCollectionValueType._ops = new Map([[
579
- "add",
580
- {
581
- process: (value, params, local, op) => {
582
- value.ackAdd(params, local, op);
706
+ IntervalCollectionValueType._ops = makeOpsMap();
707
+ function makeOpsMap() {
708
+ const rebase = (collection, op, localOpMetadata) => {
709
+ const { localSeq } = localOpMetadata;
710
+ const rebasedValue = collection.rebaseLocalInterval(op.opName, op.value, localSeq);
711
+ const rebasedOp = Object.assign(Object.assign({}, op), { value: rebasedValue });
712
+ return { rebasedOp, rebasedLocalOpMetadata: localOpMetadata };
713
+ };
714
+ return new Map([[
715
+ "add",
716
+ {
717
+ process: (collection, params, local, op) => {
718
+ collection.ackAdd(params, local, op);
719
+ },
720
+ rebase,
583
721
  },
584
- },
585
- ],
586
- [
587
- "delete",
588
- {
589
- process: (value, params, local, op) => {
590
- value.ackDelete(params, local, op);
722
+ ],
723
+ [
724
+ "delete",
725
+ {
726
+ process: (collection, params, local, op) => {
727
+ collection.ackDelete(params, local, op);
728
+ },
729
+ rebase: (collection, op, localOpMetadata) => {
730
+ // Deletion of intervals is based on id, so requires no rebasing.
731
+ return { rebasedOp: op, rebasedLocalOpMetadata: localOpMetadata };
732
+ },
591
733
  },
592
- },
593
- ],
594
- [
595
- "change",
596
- {
597
- process: (value, params, local, op) => {
598
- value.ackChange(params, local, op);
734
+ ],
735
+ [
736
+ "change",
737
+ {
738
+ process: (collection, params, local, op) => {
739
+ collection.ackChange(params, local, op);
740
+ },
741
+ rebase,
599
742
  },
600
- },
601
- ]]);
743
+ ]]);
744
+ }
602
745
  export class IntervalCollectionIterator {
603
746
  constructor(collection, iteratesForward = true, start, end) {
604
747
  this.results = [];
@@ -619,26 +762,35 @@ export class IntervalCollectionIterator {
619
762
  }
620
763
  }
621
764
  export class IntervalCollection extends TypedEventEmitter {
765
+ /** @internal */
622
766
  constructor(helpers, requiresClient, emitter, serializedIntervals) {
623
767
  super();
624
768
  this.helpers = helpers;
625
769
  this.requiresClient = requiresClient;
626
770
  this.emitter = emitter;
627
- this.savedSerializedIntervals = serializedIntervals;
771
+ this.pendingChangesStart = new Map();
772
+ this.pendingChangesEnd = new Map();
773
+ if (Array.isArray(serializedIntervals)) {
774
+ this.savedSerializedIntervals = serializedIntervals;
775
+ }
776
+ else {
777
+ this.savedSerializedIntervals =
778
+ serializedIntervals.intervals.map((i) => decompressInterval(i, serializedIntervals.label));
779
+ }
628
780
  }
629
781
  get attached() {
630
782
  return !!this.localCollection;
631
783
  }
632
784
  attachGraph(client, label) {
633
785
  if (this.attached) {
634
- throw new Error("Only supports one Sequence attach");
786
+ throw new LoggingError("Only supports one Sequence attach");
635
787
  }
636
788
  if ((client === undefined) && (this.requiresClient)) {
637
- throw new Error("Client required for this collection");
789
+ throw new LoggingError("Client required for this collection");
638
790
  }
639
791
  // Instantiate the local interval collection based on the saved intervals
640
792
  this.client = client;
641
- this.localCollection = new LocalIntervalCollection(client, label, this.helpers);
793
+ this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval) => this.emit("changeInterval", interval, true, undefined));
642
794
  if (this.savedSerializedIntervals) {
643
795
  for (const serializedInterval of this.savedSerializedIntervals) {
644
796
  this.localCollection.ensureSerializedId(serializedInterval);
@@ -647,16 +799,33 @@ export class IntervalCollection extends TypedEventEmitter {
647
799
  }
648
800
  this.savedSerializedIntervals = undefined;
649
801
  }
802
+ /**
803
+ * Gets the next local sequence number, modifying this client's collab window in doing so.
804
+ */
805
+ getNextLocalSeq() {
806
+ return ++this.client.getCollabWindow().localSeq;
807
+ }
650
808
  getIntervalById(id) {
651
809
  if (!this.attached) {
652
- throw new Error("attach must be called before accessing intervals");
810
+ throw new LoggingError("attach must be called before accessing intervals");
653
811
  }
654
812
  return this.localCollection.getIntervalById(id);
655
813
  }
814
+ /**
815
+ * Create a new interval and add it to the collection
816
+ * @param start - interval start position
817
+ * @param end - interval end position
818
+ * @param intervalType - type of the interval. All intervals are SlideOnRemove. Intervals may not be Transient.
819
+ * @param props - properties of the interval
820
+ * @returns - the created interval
821
+ */
656
822
  add(start, end, intervalType, props) {
657
823
  var _a, _b;
658
824
  if (!this.attached) {
659
- throw new Error("attach must be called prior to adding intervals");
825
+ throw new LoggingError("attach must be called prior to adding intervals");
826
+ }
827
+ if (intervalType & IntervalType.Transient) {
828
+ throw new LoggingError("Can not add transient intervals");
660
829
  }
661
830
  const interval = this.localCollection.addInterval(start, end, intervalType, props);
662
831
  if (interval) {
@@ -668,7 +837,7 @@ export class IntervalCollection extends TypedEventEmitter {
668
837
  start,
669
838
  };
670
839
  // Local ops get submitted to the server. Remote ops have the deserializer run.
671
- this.emitter.emit("add", undefined, serializedInterval);
840
+ this.emitter.emit("add", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
672
841
  }
673
842
  this.emit("addInterval", interval, true, undefined);
674
843
  return interval;
@@ -679,7 +848,7 @@ export class IntervalCollection extends TypedEventEmitter {
679
848
  if (interval) {
680
849
  // Local ops get submitted to the server. Remote ops have the deserializer run.
681
850
  if (local) {
682
- this.emitter.emit("delete", undefined, interval.serialize(this.client));
851
+ this.emitter.emit("delete", undefined, interval.serialize(this.client), { localSeq: this.getNextLocalSeq() });
683
852
  }
684
853
  else {
685
854
  if (this.onDeserialize) {
@@ -698,40 +867,41 @@ export class IntervalCollection extends TypedEventEmitter {
698
867
  }
699
868
  changeProperties(id, props) {
700
869
  if (!this.attached) {
701
- throw new Error("Attach must be called before accessing intervals");
870
+ throw new LoggingError("Attach must be called before accessing intervals");
702
871
  }
703
872
  if (typeof (id) !== "string") {
704
- throw new Error("Change API requires an ID that is a string");
873
+ throw new LoggingError("Change API requires an ID that is a string");
705
874
  }
706
875
  if (!props) {
707
- throw new Error("changeProperties should be called with a property set");
876
+ throw new LoggingError("changeProperties should be called with a property set");
708
877
  }
709
878
  const interval = this.getIntervalById(id);
710
879
  if (interval) {
711
880
  // Pass Unassigned as the sequence number to indicate that this is a local op that is waiting for an ack.
712
881
  const deltaProps = interval.addProperties(props, true, UnassignedSequenceNumber);
713
882
  const serializedInterval = interval.serialize(this.client);
714
- // Emit a change op that will only change properties. Add the ID to the property bag provided by the caller.
883
+ // Emit a change op that will only change properties. Add the ID to
884
+ // the property bag provided by the caller.
715
885
  serializedInterval.start = undefined;
716
886
  serializedInterval.end = undefined;
717
887
  serializedInterval.properties = props;
718
888
  serializedInterval.properties[reservedIntervalIdKey] = interval.getIntervalId();
719
- this.emitter.emit("change", undefined, serializedInterval);
889
+ this.emitter.emit("change", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
720
890
  this.emit("propertyChanged", interval, deltaProps);
721
891
  }
722
892
  this.emit("changeInterval", interval, true, undefined);
723
893
  }
724
894
  change(id, start, end) {
725
895
  if (!this.attached) {
726
- throw new Error("Attach must be called before accessing intervals");
896
+ throw new LoggingError("Attach must be called before accessing intervals");
727
897
  }
898
+ // Force id to be a string.
728
899
  if (typeof (id) !== "string") {
729
- throw new Error("Change API requires an ID that is a string");
900
+ throw new LoggingError("Change API requires an ID that is a string");
730
901
  }
731
- // Force id to be a string.
732
902
  const interval = this.getIntervalById(id);
733
903
  if (interval) {
734
- this.localCollection.changeInterval(interval, start, end);
904
+ const newInterval = this.localCollection.changeInterval(interval, start, end);
735
905
  const serializedInterval = interval.serialize(this.client);
736
906
  serializedInterval.start = start;
737
907
  serializedInterval.end = end;
@@ -740,23 +910,19 @@ export class IntervalCollection extends TypedEventEmitter {
740
910
  {
741
911
  [reservedIntervalIdKey]: interval.getIntervalId(),
742
912
  };
743
- this.emitter.emit("change", undefined, serializedInterval);
913
+ this.emitter.emit("change", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
744
914
  this.addPendingChange(id, serializedInterval);
915
+ this.emit("changeInterval", newInterval, true, undefined);
916
+ return newInterval;
745
917
  }
746
- this.emit("changeInterval", interval, true, undefined);
747
- return interval;
918
+ // No interval to change
919
+ return undefined;
748
920
  }
749
921
  addPendingChange(id, serializedInterval) {
750
922
  if (serializedInterval.start !== undefined) {
751
- if (!this.pendingChangesStart) {
752
- this.pendingChangesStart = new Map();
753
- }
754
923
  this.addPendingChangeHelper(id, this.pendingChangesStart, serializedInterval);
755
924
  }
756
925
  if (serializedInterval.end !== undefined) {
757
- if (!this.pendingChangesEnd) {
758
- this.pendingChangesEnd = new Map();
759
- }
760
926
  this.addPendingChangeHelper(id, this.pendingChangesEnd, serializedInterval);
761
927
  }
762
928
  }
@@ -769,8 +935,9 @@ export class IntervalCollection extends TypedEventEmitter {
769
935
  entries.push(serializedInterval);
770
936
  }
771
937
  removePendingChange(serializedInterval) {
938
+ var _a;
772
939
  // Change ops always have an ID.
773
- const id = serializedInterval.properties[reservedIntervalIdKey];
940
+ const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
774
941
  if (serializedInterval.start !== undefined) {
775
942
  this.removePendingChangeHelper(id, this.pendingChangesStart, serializedInterval);
776
943
  }
@@ -779,26 +946,24 @@ export class IntervalCollection extends TypedEventEmitter {
779
946
  }
780
947
  }
781
948
  removePendingChangeHelper(id, pendingChanges, serializedInterval) {
782
- const entries = pendingChanges === null || pendingChanges === void 0 ? void 0 : pendingChanges.get(id);
949
+ const entries = pendingChanges.get(id);
783
950
  if (entries) {
784
951
  const pendingChange = entries.shift();
785
952
  if (entries.length === 0) {
786
953
  pendingChanges.delete(id);
787
954
  }
788
- if (pendingChange.start !== serializedInterval.start ||
789
- pendingChange.end !== serializedInterval.end) {
790
- throw new Error("Mismatch in pending changes");
955
+ if ((pendingChange === null || pendingChange === void 0 ? void 0 : pendingChange.start) !== serializedInterval.start ||
956
+ (pendingChange === null || pendingChange === void 0 ? void 0 : pendingChange.end) !== serializedInterval.end) {
957
+ throw new LoggingError("Mismatch in pending changes");
791
958
  }
792
959
  }
793
960
  }
794
961
  hasPendingChangeStart(id) {
795
- var _a;
796
- const entries = (_a = this.pendingChangesStart) === null || _a === void 0 ? void 0 : _a.get(id);
962
+ const entries = this.pendingChangesStart.get(id);
797
963
  return entries && entries.length !== 0;
798
964
  }
799
965
  hasPendingChangeEnd(id) {
800
- var _a;
801
- const entries = (_a = this.pendingChangesEnd) === null || _a === void 0 ? void 0 : _a.get(id);
966
+ const entries = this.pendingChangesEnd.get(id);
802
967
  return entries && entries.length !== 0;
803
968
  }
804
969
  /** @deprecated - use ackChange */
@@ -807,22 +972,23 @@ export class IntervalCollection extends TypedEventEmitter {
807
972
  }
808
973
  /** @internal */
809
974
  ackChange(serializedInterval, local, op) {
810
- var _a, _b;
975
+ var _a, _b, _c, _d;
811
976
  if (!this.attached) {
812
- throw new Error("Attach must be called before accessing intervals");
977
+ throw new LoggingError("Attach must be called before accessing intervals");
813
978
  }
814
979
  let interval;
815
980
  if (local) {
816
981
  // This is an ack from the server. Remove the pending change.
817
982
  this.removePendingChange(serializedInterval);
818
- const id = serializedInterval.properties[reservedIntervalIdKey];
983
+ const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
819
984
  interval = this.getIntervalById(id);
820
985
  if (interval) {
821
986
  // Let the propertyManager prune its pending change-properties set.
822
- (_a = interval.propertyManager) === null || _a === void 0 ? void 0 : _a.ackPendingProperties({
823
- type: 2 /* ANNOTATE */,
824
- props: serializedInterval.properties,
987
+ (_b = interval.propertyManager) === null || _b === void 0 ? void 0 : _b.ackPendingProperties({
988
+ type: MergeTreeDeltaType.ANNOTATE,
989
+ props: (_c = serializedInterval.properties) !== null && _c !== void 0 ? _c : {},
825
990
  });
991
+ this.ackInterval(interval, op);
826
992
  }
827
993
  }
828
994
  else {
@@ -831,7 +997,7 @@ export class IntervalCollection extends TypedEventEmitter {
831
997
  // Note that the ID is in the property bag only to allow us to find the interval.
832
998
  // This API cannot change the ID, and writing to the ID property will result in an exception. So we
833
999
  // strip it out of the properties here.
834
- const _c = serializedInterval.properties, _d = reservedIntervalIdKey, id = _c[_d], newProps = __rest(_c, [typeof _d === "symbol" ? _d : _d + ""]);
1000
+ const _e = serializedInterval.properties, _f = reservedIntervalIdKey, id = _e[_f], newProps = __rest(_e, [typeof _f === "symbol" ? _f : _f + ""]);
835
1001
  interval = this.getIntervalById(id);
836
1002
  if (interval) {
837
1003
  let start;
@@ -846,7 +1012,7 @@ export class IntervalCollection extends TypedEventEmitter {
846
1012
  if (start !== undefined || end !== undefined) {
847
1013
  // If changeInterval gives us a new interval, work with that one. Otherwise keep working with
848
1014
  // the one we originally found in the tree.
849
- interval = (_b = this.localCollection.changeInterval(interval, start, end, op)) !== null && _b !== void 0 ? _b : interval;
1015
+ interval = (_d = this.localCollection.changeInterval(interval, start, end, op)) !== null && _d !== void 0 ? _d : interval;
850
1016
  }
851
1017
  const deltaProps = interval.addProperties(newProps, true, op.sequenceNumber);
852
1018
  if (this.onDeserialize) {
@@ -861,7 +1027,7 @@ export class IntervalCollection extends TypedEventEmitter {
861
1027
  }
862
1028
  addConflictResolver(conflictResolver) {
863
1029
  if (!this.attached) {
864
- throw new Error("attachSequence must be called");
1030
+ throw new LoggingError("attachSequence must be called");
865
1031
  }
866
1032
  this.localCollection.addConflictResolver(conflictResolver);
867
1033
  }
@@ -874,22 +1040,109 @@ export class IntervalCollection extends TypedEventEmitter {
874
1040
  this.onDeserialize = onDeserialize;
875
1041
  // Trigger the async prepare work across all values in the collection
876
1042
  this.localCollection.map((interval) => {
877
- this.onDeserialize(interval);
1043
+ onDeserialize(interval);
878
1044
  });
879
1045
  }
1046
+ /** @internal */
1047
+ rebaseLocalInterval(opName, serializedInterval, localSeq) {
1048
+ var _a, _b;
1049
+ if (!this.attached) {
1050
+ throw new LoggingError("attachSequence must be called");
1051
+ }
1052
+ const { start, end, intervalType, properties, sequenceNumber } = serializedInterval;
1053
+ const startRebased = start === undefined ? undefined :
1054
+ this.client.rebasePosition(start, sequenceNumber, localSeq);
1055
+ const endRebased = end === undefined ? undefined :
1056
+ this.client.rebasePosition(end, sequenceNumber, localSeq);
1057
+ const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
1058
+ const rebased = {
1059
+ start: startRebased,
1060
+ end: endRebased,
1061
+ intervalType,
1062
+ sequenceNumber: (_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.getCurrentSeq()) !== null && _b !== void 0 ? _b : 0,
1063
+ properties,
1064
+ };
1065
+ if (opName === "change" && (this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
1066
+ this.removePendingChange(serializedInterval);
1067
+ this.addPendingChange(intervalId, rebased);
1068
+ }
1069
+ return rebased;
1070
+ }
1071
+ getSlideToSegment(lref) {
1072
+ const segoff = { segment: lref.segment, offset: lref.offset };
1073
+ const newSegoff = this.client.getSlideToSegment(segoff);
1074
+ const value = (segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset) ? undefined : newSegoff;
1075
+ return value;
1076
+ }
1077
+ setSlideOnRemove(lref) {
1078
+ let refType = lref.refType;
1079
+ refType = refType & ~ReferenceType.StayOnRemove;
1080
+ refType = refType | ReferenceType.SlideOnRemove;
1081
+ lref.refType = refType;
1082
+ }
1083
+ ackInterval(interval, op) {
1084
+ // in current usage, interval is always a SequenceInterval
1085
+ if (!(interval instanceof SequenceInterval)) {
1086
+ return;
1087
+ }
1088
+ if (!refTypeIncludesFlag(interval.start, ReferenceType.StayOnRemove) &&
1089
+ !refTypeIncludesFlag(interval.end, ReferenceType.StayOnRemove)) {
1090
+ return;
1091
+ }
1092
+ const newStart = this.getSlideToSegment(interval.start);
1093
+ const newEnd = this.getSlideToSegment(interval.end);
1094
+ const id = interval.properties[reservedIntervalIdKey];
1095
+ const hasPendingStartChange = this.hasPendingChangeStart(id);
1096
+ const hasPendingEndChange = this.hasPendingChangeEnd(id);
1097
+ if (!hasPendingStartChange) {
1098
+ this.setSlideOnRemove(interval.start);
1099
+ }
1100
+ if (!hasPendingEndChange) {
1101
+ this.setSlideOnRemove(interval.end);
1102
+ }
1103
+ const needsStartUpdate = newStart !== undefined && !hasPendingStartChange;
1104
+ const needsEndUpdate = newEnd !== undefined && !hasPendingEndChange;
1105
+ if (needsStartUpdate || needsEndUpdate) {
1106
+ // In this case, where we change the start or end of an interval,
1107
+ // it is necessary to remove and re-add the interval listeners.
1108
+ // This ensures that the correct listeners are added to the ReferencePosition.
1109
+ this.localCollection.removeExistingInterval(interval);
1110
+ if (needsStartUpdate) {
1111
+ const props = interval.start.properties;
1112
+ this.client.removeLocalReferencePosition(interval.start);
1113
+ interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op);
1114
+ if (props) {
1115
+ interval.start.addProperties(props);
1116
+ }
1117
+ }
1118
+ if (needsEndUpdate) {
1119
+ const props = interval.end.properties;
1120
+ this.client.removeLocalReferencePosition(interval.end);
1121
+ interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op);
1122
+ if (props) {
1123
+ interval.end.addProperties(props);
1124
+ }
1125
+ }
1126
+ this.localCollection.add(interval);
1127
+ }
1128
+ }
880
1129
  /** @deprecated - use ackAdd */
881
1130
  addInternal(serializedInterval, local, op) {
882
1131
  return this.ackAdd(serializedInterval, local, op);
883
1132
  }
884
1133
  /** @internal */
885
1134
  ackAdd(serializedInterval, local, op) {
1135
+ var _a;
886
1136
  if (local) {
887
- // Local ops were applied when the message was created and there's no "pending add"
888
- // state to bookkeep
1137
+ const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
1138
+ const localInterval = this.getIntervalById(id);
1139
+ if (localInterval) {
1140
+ this.ackInterval(localInterval, op);
1141
+ }
889
1142
  return;
890
1143
  }
891
1144
  if (!this.attached) {
892
- throw new Error("attachSequence must be called");
1145
+ throw new LoggingError("attachSequence must be called");
893
1146
  }
894
1147
  this.localCollection.ensureSerializedId(serializedInterval);
895
1148
  const interval = this.localCollection.addInterval(serializedInterval.start, serializedInterval.end, serializedInterval.intervalType, serializedInterval.properties, op);
@@ -914,17 +1167,20 @@ export class IntervalCollection extends TypedEventEmitter {
914
1167
  return;
915
1168
  }
916
1169
  if (!this.attached) {
917
- throw new Error("attach must be called prior to deleting intervals");
1170
+ throw new LoggingError("attach must be called prior to deleting intervals");
918
1171
  }
919
- this.localCollection.ensureSerializedId(serializedInterval);
920
- const interval = this.localCollection.getIntervalById(serializedInterval.properties[reservedIntervalIdKey]);
1172
+ const id = this.localCollection.ensureSerializedId(serializedInterval);
1173
+ const interval = this.localCollection.getIntervalById(id);
921
1174
  if (interval) {
922
1175
  this.deleteExistingInterval(interval, local, op);
923
1176
  }
924
1177
  }
1178
+ /**
1179
+ * @internal
1180
+ */
925
1181
  serializeInternal() {
926
1182
  if (!this.attached) {
927
- throw new Error("attachSequence must be called");
1183
+ throw new LoggingError("attachSequence must be called");
928
1184
  }
929
1185
  return this.localCollection.serialize();
930
1186
  }
@@ -956,25 +1212,25 @@ export class IntervalCollection extends TypedEventEmitter {
956
1212
  }
957
1213
  findOverlappingIntervals(startPosition, endPosition) {
958
1214
  if (!this.attached) {
959
- throw new Error("attachSequence must be called");
1215
+ throw new LoggingError("attachSequence must be called");
960
1216
  }
961
1217
  return this.localCollection.findOverlappingIntervals(startPosition, endPosition);
962
1218
  }
963
1219
  map(fn) {
964
1220
  if (!this.attached) {
965
- throw new Error("attachSequence must be called");
1221
+ throw new LoggingError("attachSequence must be called");
966
1222
  }
967
1223
  this.localCollection.map(fn);
968
1224
  }
969
1225
  previousInterval(pos) {
970
1226
  if (!this.attached) {
971
- throw new Error("attachSequence must be called");
1227
+ throw new LoggingError("attachSequence must be called");
972
1228
  }
973
1229
  return this.localCollection.previousInterval(pos);
974
1230
  }
975
1231
  nextInterval(pos) {
976
1232
  if (!this.attached) {
977
- throw new Error("attachSequence must be called");
1233
+ throw new LoggingError("attachSequence must be called");
978
1234
  }
979
1235
  return this.localCollection.nextInterval(pos);
980
1236
  }