@fluidframework/sequence 2.0.0-rc.4.0.6 → 2.0.0-rc.5.0.1

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 (168) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/api-extractor/api-extractor-lint-beta.cjs.json +5 -0
  3. package/api-extractor/api-extractor-lint-beta.esm.json +5 -0
  4. package/api-extractor/api-extractor-lint-bundle.json +5 -0
  5. package/api-extractor/api-extractor-lint-legacy.cjs.json +5 -0
  6. package/api-extractor/api-extractor-lint-legacy.esm.json +5 -0
  7. package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
  8. package/api-extractor/api-extractor-lint-public.esm.json +5 -0
  9. package/api-extractor.json +1 -1
  10. package/api-report/{sequence.api.md → sequence.alpha.api.md} +71 -244
  11. package/api-report/sequence.beta.api.md +83 -0
  12. package/api-report/sequence.public.api.md +83 -0
  13. package/biome.jsonc +4 -0
  14. package/dist/IntervalCollectionValues.d.ts +1 -1
  15. package/dist/IntervalCollectionValues.d.ts.map +1 -1
  16. package/dist/IntervalCollectionValues.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/intervalCollection.d.ts +1 -1
  21. package/dist/intervalCollection.d.ts.map +1 -1
  22. package/dist/intervalCollection.js +4 -6
  23. package/dist/intervalCollection.js.map +1 -1
  24. package/dist/intervalCollectionMap.d.ts +2 -2
  25. package/dist/intervalCollectionMap.d.ts.map +1 -1
  26. package/dist/intervalCollectionMap.js.map +1 -1
  27. package/dist/intervalCollectionMapInterfaces.d.ts +2 -2
  28. package/dist/intervalCollectionMapInterfaces.d.ts.map +1 -1
  29. package/dist/intervalCollectionMapInterfaces.js.map +1 -1
  30. package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
  31. package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -1
  32. package/dist/intervalIndex/endpointIndex.d.ts.map +1 -1
  33. package/dist/intervalIndex/endpointIndex.js.map +1 -1
  34. package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  35. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
  36. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +0 -3
  37. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  38. package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
  39. package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -1
  40. package/dist/intervalTree.js.map +1 -1
  41. package/dist/intervals/interval.d.ts +1 -1
  42. package/dist/intervals/interval.d.ts.map +1 -1
  43. package/dist/intervals/interval.js.map +1 -1
  44. package/dist/intervals/intervalUtils.d.ts +2 -2
  45. package/dist/intervals/intervalUtils.d.ts.map +1 -1
  46. package/dist/intervals/intervalUtils.js +0 -1
  47. package/dist/intervals/intervalUtils.js.map +1 -1
  48. package/dist/intervals/sequenceInterval.d.ts +1 -1
  49. package/dist/intervals/sequenceInterval.d.ts.map +1 -1
  50. package/dist/intervals/sequenceInterval.js +1 -1
  51. package/dist/intervals/sequenceInterval.js.map +1 -1
  52. package/dist/legacy.d.ts +1 -0
  53. package/dist/packageVersion.d.ts +1 -1
  54. package/dist/packageVersion.js +1 -1
  55. package/dist/packageVersion.js.map +1 -1
  56. package/dist/revertibles.d.ts.map +1 -1
  57. package/dist/revertibles.js +3 -3
  58. package/dist/revertibles.js.map +1 -1
  59. package/dist/sequence.d.ts +168 -133
  60. package/dist/sequence.d.ts.map +1 -1
  61. package/dist/sequence.js +59 -240
  62. package/dist/sequence.js.map +1 -1
  63. package/dist/sequenceDeltaEvent.js.map +1 -1
  64. package/dist/sequenceFactory.d.ts +2 -3
  65. package/dist/sequenceFactory.d.ts.map +1 -1
  66. package/dist/sequenceFactory.js.map +1 -1
  67. package/dist/sharedIntervalCollection.d.ts +4 -5
  68. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  69. package/dist/sharedIntervalCollection.js +5 -5
  70. package/dist/sharedIntervalCollection.js.map +1 -1
  71. package/dist/sharedSequence.d.ts +1 -2
  72. package/dist/sharedSequence.d.ts.map +1 -1
  73. package/dist/sharedSequence.js.map +1 -1
  74. package/dist/sharedString.d.ts +3 -3
  75. package/dist/sharedString.d.ts.map +1 -1
  76. package/dist/sharedString.js.map +1 -1
  77. package/lib/IntervalCollectionValues.d.ts +1 -1
  78. package/lib/IntervalCollectionValues.d.ts.map +1 -1
  79. package/lib/IntervalCollectionValues.js +1 -1
  80. package/lib/IntervalCollectionValues.js.map +1 -1
  81. package/lib/index.d.ts +1 -1
  82. package/lib/index.d.ts.map +1 -1
  83. package/lib/index.js +1 -1
  84. package/lib/index.js.map +1 -1
  85. package/lib/intervalCollection.d.ts +1 -1
  86. package/lib/intervalCollection.d.ts.map +1 -1
  87. package/lib/intervalCollection.js +4 -6
  88. package/lib/intervalCollection.js.map +1 -1
  89. package/lib/intervalCollectionMap.d.ts +2 -2
  90. package/lib/intervalCollectionMap.d.ts.map +1 -1
  91. package/lib/intervalCollectionMap.js +1 -1
  92. package/lib/intervalCollectionMap.js.map +1 -1
  93. package/lib/intervalCollectionMapInterfaces.d.ts +2 -2
  94. package/lib/intervalCollectionMapInterfaces.d.ts.map +1 -1
  95. package/lib/intervalCollectionMapInterfaces.js.map +1 -1
  96. package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
  97. package/lib/intervalIndex/endpointInRangeIndex.js +1 -1
  98. package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -1
  99. package/lib/intervalIndex/endpointIndex.d.ts.map +1 -1
  100. package/lib/intervalIndex/endpointIndex.js.map +1 -1
  101. package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  102. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
  103. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +0 -3
  104. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  105. package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
  106. package/lib/intervalIndex/startpointInRangeIndex.js +1 -1
  107. package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -1
  108. package/lib/intervalTree.js.map +1 -1
  109. package/lib/intervals/interval.d.ts +1 -1
  110. package/lib/intervals/interval.d.ts.map +1 -1
  111. package/lib/intervals/interval.js.map +1 -1
  112. package/lib/intervals/intervalUtils.d.ts +2 -2
  113. package/lib/intervals/intervalUtils.d.ts.map +1 -1
  114. package/lib/intervals/intervalUtils.js +0 -1
  115. package/lib/intervals/intervalUtils.js.map +1 -1
  116. package/lib/intervals/sequenceInterval.d.ts +1 -1
  117. package/lib/intervals/sequenceInterval.d.ts.map +1 -1
  118. package/lib/intervals/sequenceInterval.js +1 -1
  119. package/lib/intervals/sequenceInterval.js.map +1 -1
  120. package/lib/legacy.d.ts +1 -0
  121. package/lib/packageVersion.d.ts +1 -1
  122. package/lib/packageVersion.js +1 -1
  123. package/lib/packageVersion.js.map +1 -1
  124. package/lib/revertibles.d.ts.map +1 -1
  125. package/lib/revertibles.js +3 -3
  126. package/lib/revertibles.js.map +1 -1
  127. package/lib/sequence.d.ts +168 -133
  128. package/lib/sequence.d.ts.map +1 -1
  129. package/lib/sequence.js +42 -223
  130. package/lib/sequence.js.map +1 -1
  131. package/lib/sequenceDeltaEvent.js.map +1 -1
  132. package/lib/sequenceFactory.d.ts +2 -3
  133. package/lib/sequenceFactory.d.ts.map +1 -1
  134. package/lib/sequenceFactory.js.map +1 -1
  135. package/lib/sharedIntervalCollection.d.ts +4 -5
  136. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  137. package/lib/sharedIntervalCollection.js +2 -2
  138. package/lib/sharedIntervalCollection.js.map +1 -1
  139. package/lib/sharedSequence.d.ts +1 -2
  140. package/lib/sharedSequence.d.ts.map +1 -1
  141. package/lib/sharedSequence.js.map +1 -1
  142. package/lib/sharedString.d.ts +3 -3
  143. package/lib/sharedString.d.ts.map +1 -1
  144. package/lib/sharedString.js.map +1 -1
  145. package/lib/tsdoc-metadata.json +1 -1
  146. package/package.json +77 -30
  147. package/src/IntervalCollectionValues.ts +8 -3
  148. package/src/index.ts +5 -1
  149. package/src/intervalCollection.ts +29 -18
  150. package/src/intervalCollectionMap.ts +6 -4
  151. package/src/intervalCollectionMapInterfaces.ts +2 -2
  152. package/src/intervalIndex/endpointInRangeIndex.ts +28 -22
  153. package/src/intervalIndex/endpointIndex.ts +3 -1
  154. package/src/intervalIndex/overlappingIntervalsIndex.ts +2 -2
  155. package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +0 -3
  156. package/src/intervalIndex/startpointInRangeIndex.ts +26 -20
  157. package/src/intervals/interval.ts +12 -9
  158. package/src/intervals/intervalUtils.ts +13 -5
  159. package/src/intervals/sequenceInterval.ts +2 -2
  160. package/src/packageVersion.ts +1 -1
  161. package/src/revertibles.ts +15 -11
  162. package/src/sequence.ts +302 -277
  163. package/src/sequenceFactory.ts +3 -5
  164. package/src/sharedIntervalCollection.ts +12 -6
  165. package/src/sharedSequence.ts +5 -2
  166. package/src/sharedString.ts +11 -4
  167. package/tsconfig.json +2 -0
  168. package/tsdoc.json +4 -0
package/src/sequence.ts CHANGED
@@ -5,12 +5,16 @@
5
5
 
6
6
  import { bufferToString } from "@fluid-internal/client-utils";
7
7
  import { IEventThisPlaceHolder } from "@fluidframework/core-interfaces";
8
- import { assert, Deferred } from "@fluidframework/core-utils/internal";
8
+ import { assert } from "@fluidframework/core-utils/internal";
9
9
  import {
10
10
  IChannelAttributes,
11
- IChannelStorageService,
12
11
  IFluidDataStoreRuntime,
13
- } from "@fluidframework/datastore-definitions";
12
+ IChannelStorageService,
13
+ } from "@fluidframework/datastore-definitions/internal";
14
+ import {
15
+ MessageType,
16
+ ISequencedDocumentMessage,
17
+ } from "@fluidframework/driver-definitions/internal";
14
18
  import {
15
19
  // eslint-disable-next-line import/no-deprecated
16
20
  Client,
@@ -43,15 +47,27 @@ import {
43
47
  createRemoveRangeOp,
44
48
  matchProperties,
45
49
  } from "@fluidframework/merge-tree/internal";
46
- import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
47
- import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
48
- import { ObjectStoragePartition, SummaryTreeBuilder } from "@fluidframework/runtime-utils/internal";
49
- import { IFluidSerializer, ISharedObjectEvents } from "@fluidframework/shared-object-base";
50
- import { SharedObject } from "@fluidframework/shared-object-base/internal";
50
+ import {
51
+ ISummaryTreeWithStats,
52
+ ITelemetryContext,
53
+ } from "@fluidframework/runtime-definitions/internal";
54
+ import {
55
+ ObjectStoragePartition,
56
+ SummaryTreeBuilder,
57
+ } from "@fluidframework/runtime-utils/internal";
58
+ import {
59
+ IFluidSerializer,
60
+ ISharedObjectEvents,
61
+ SharedObject,
62
+ type ISharedObject,
63
+ } from "@fluidframework/shared-object-base/internal";
51
64
  import { LoggingError, createChildLogger } from "@fluidframework/telemetry-utils/internal";
52
65
  import Deque from "double-ended-queue";
53
66
 
54
- import { IIntervalCollection, SequenceIntervalCollectionValueType } from "./intervalCollection.js";
67
+ import {
68
+ IIntervalCollection,
69
+ SequenceIntervalCollectionValueType,
70
+ } from "./intervalCollection.js";
55
71
  import { IMapOperation, IntervalCollectionMap } from "./intervalCollectionMap.js";
56
72
  import { IMapMessageLocalMetadata, IValueChanged } from "./intervalCollectionMapInterfaces.js";
57
73
  import { SequenceInterval } from "./intervals/index.js";
@@ -110,15 +126,225 @@ export interface ISharedSegmentSequenceEvents extends ISharedObjectEvents {
110
126
  ): void;
111
127
  }
112
128
 
129
+ /**
130
+ * @alpha
131
+ */
132
+ export interface ISharedSegmentSequence<T extends ISegment>
133
+ extends ISharedObject<ISharedSegmentSequenceEvents>,
134
+ ISharedIntervalCollection<SequenceInterval>,
135
+ MergeTreeRevertibleDriver {
136
+ /**
137
+ * Creates a `LocalReferencePosition` on this SharedString. If the refType does not include
138
+ * ReferenceType.Transient, the returned reference will be added to the localRefs on the provided segment.
139
+ * @param segment - Segment to add the local reference on
140
+ * @param offset - Offset on the segment at which to place the local reference
141
+ * @param refType - ReferenceType for the created local reference
142
+ * @param properties - PropertySet to place on the created local reference
143
+ */
144
+ createLocalReferencePosition(
145
+ segment: T,
146
+ offset: number,
147
+ refType: ReferenceType,
148
+ properties: PropertySet | undefined,
149
+ slidingPreference?: SlidingPreference,
150
+ canSlideToEndpoint?: boolean,
151
+ ): LocalReferencePosition;
152
+
153
+ /**
154
+ * Removes a `LocalReferencePosition` from this SharedString.
155
+ */
156
+ removeLocalReferencePosition(
157
+ lref: LocalReferencePosition,
158
+ ): LocalReferencePosition | undefined;
159
+
160
+ /**
161
+ * Returns the length of the current sequence for the client
162
+ */
163
+ getLength(): number;
164
+
165
+ /**
166
+ * Returns the current position of a segment, and -1 if the segment
167
+ * does not exist in this sequence
168
+ * @param segment - The segment to get the position of
169
+ */
170
+ getPosition(segment: ISegment): number;
171
+
172
+ /**
173
+ * Resolves a `ReferencePosition` into a character position using this client's perspective.
174
+ *
175
+ * Reference positions that point to a character that has been removed will
176
+ * always return the position of the nearest non-removed character, regardless
177
+ * of `ReferenceType`. To handle this case specifically, one may wish
178
+ * to look at the segment returned by `ReferencePosition.getSegment`.
179
+ */
180
+ localReferencePositionToPosition(lref: ReferencePosition): number;
181
+
182
+ /**
183
+ * Walk the underlying segments of the sequence.
184
+ * The walked segments may extend beyond the range if the segments cross the
185
+ * ranges start or end boundaries.
186
+ *
187
+ * Set split range to true to ensure only segments within the range are walked.
188
+ *
189
+ * @param handler - The function to handle each segment. Traversal ends if
190
+ * this function returns true.
191
+ * @param start - Optional. The start of range walk.
192
+ * @param end - Optional. The end of range walk
193
+ * @param accum - Optional. An object that will be passed to the handler for accumulation
194
+ * @param splitRange - Optional. Splits boundary segments on the range boundaries. Defaults to false.
195
+ */
196
+ walkSegments<TClientData>(
197
+ handler: ISegmentAction<TClientData>,
198
+ start?: number,
199
+ end?: number,
200
+ accum?: TClientData,
201
+ splitRange?: boolean,
202
+ ): void;
203
+
204
+ /**
205
+ * Inserts a segment directly before a `ReferencePosition`.
206
+ * @param refPos - The reference position to insert the segment at
207
+ * @param segment - The segment to insert
208
+ */
209
+ insertAtReferencePosition(pos: ReferencePosition, segment: T): void;
210
+
211
+ /**
212
+ * Finds the segment information (i.e. segment + offset) corresponding to a character position in the SharedString.
213
+ * If the position is past the end of the string, `segment` and `offset` on the returned object may be undefined.
214
+ * @param pos - Character position (index) into the current local view of the SharedString.
215
+ */
216
+ getContainingSegment(pos: number): {
217
+ segment: T | undefined;
218
+ offset: number | undefined;
219
+ };
220
+
221
+ getPropertiesAtPosition(pos: number): PropertySet | undefined;
222
+
223
+ /**
224
+ * @returns An iterable object that enumerates the IntervalCollection labels.
225
+ *
226
+ * @example
227
+ *
228
+ * ```typescript
229
+ * const iter = this.getIntervalCollectionKeys();
230
+ * for (key of iter)
231
+ * const collection = this.getIntervalCollection(key);
232
+ * ...
233
+ * ```
234
+ */
235
+ getIntervalCollectionLabels(): IterableIterator<string>;
236
+
237
+ /**
238
+ * Retrieves the interval collection keyed on `label`. If no such interval collection exists,
239
+ * creates one.
240
+ */
241
+ getIntervalCollection(label: string): IIntervalCollection<SequenceInterval>;
242
+
243
+ /**
244
+ * Obliterate is similar to remove, but differs in that segments concurrently
245
+ * inserted into an obliterated range will also be removed
246
+ *
247
+ * @param start - The inclusive start of the range to obliterate
248
+ * @param end - The exclusive end of the range to obliterate
249
+ */
250
+ obliterateRange(start: number, end: number): void;
251
+
252
+ /**
253
+ * @returns The most recent sequence number which has been acked by the server and processed by this
254
+ * SharedSegmentSequence.
255
+ */
256
+ getCurrentSeq(): number;
257
+
258
+ /**
259
+ * Annotates the range with the provided properties
260
+ *
261
+ * @param start - The inclusive start position of the range to annotate
262
+ * @param end - The exclusive end position of the range to annotate
263
+ * @param props - The properties to annotate the range with
264
+ *
265
+ */
266
+ annotateRange(start: number, end: number, props: PropertySet): void;
267
+
268
+ /**
269
+ * @param start - The inclusive start of the range to remove
270
+ * @param end - The exclusive end of the range to remove
271
+ */
272
+ removeRange(start: number, end: number): void;
273
+
274
+ /**
275
+ * Resolves a remote client's position against the local sequence
276
+ * and returns the remote client's position relative to the local
277
+ * sequence. The client ref seq must be above the minimum sequence number
278
+ * or the return value will be undefined.
279
+ * Generally this method is used in conjunction with signals which provide
280
+ * point in time values for the below parameters, and is useful for things
281
+ * like displaying user position. It should not be used with persisted values
282
+ * as persisted values will quickly become invalid as the remoteClientRefSeq
283
+ * moves below the minimum sequence number
284
+ * @param remoteClientPosition - The remote client's position to resolve
285
+ * @param remoteClientRefSeq - The reference sequence number of the remote client
286
+ * @param remoteClientId - The client id of the remote client
287
+ */
288
+ resolveRemoteClientPosition(
289
+ remoteClientPosition: number,
290
+ remoteClientRefSeq: number,
291
+ remoteClientId: string,
292
+ ): number | undefined;
293
+
294
+ // #region APIs we might want to remove
295
+ /**
296
+ * Initializes the object as a local, non-shared object. This object can become shared after
297
+ * it is attached to the document.
298
+ * @privateRemarks
299
+ * TODO: determine if this API (from SharedObject) is needed by users of the encapsulated API, declarative API or both,
300
+ * and handle exposing it in a consistent way for all SharedObjects if needed.
301
+ */
302
+ initializeLocal(): void;
303
+
304
+ /**
305
+ * @deprecated The ability to create group ops will be removed in an upcoming
306
+ * release, as group ops are redundant with the native batching capabilities
307
+ * of the runtime
308
+ */
309
+ // eslint-disable-next-line import/no-deprecated
310
+ groupOperation(groupOp: IMergeTreeGroupMsg): void;
311
+
312
+ getRangeExtentsOfPosition(pos: number): {
313
+ posStart: number | undefined;
314
+ posAfterEnd: number | undefined;
315
+ };
316
+
317
+ /**
318
+ * Inserts a segment
319
+ * @param start - The position to insert the segment at
320
+ * @param spec - The segment to inserts spec
321
+ */
322
+ insertFromSpec(pos: number, spec: IJSONSegment): void;
323
+
324
+ /**
325
+ * Given a position specified relative to a marker id, lookup the marker
326
+ * and convert the position to a character position.
327
+ * @param relativePos - Id of marker (may be indirect) and whether position is before or after marker.
328
+ */
329
+ posFromRelativePos(relativePos: IRelativePosition): number;
330
+
331
+ // #endregion
332
+ }
333
+
113
334
  /**
114
335
  * @alpha
115
336
  */
116
337
  export abstract class SharedSegmentSequence<T extends ISegment>
117
338
  extends SharedObject<ISharedSegmentSequenceEvents>
118
- implements ISharedIntervalCollection<SequenceInterval>, MergeTreeRevertibleDriver
339
+ implements ISharedSegmentSequence<T>
119
340
  {
341
+ /**
342
+ * This promise is always immediately resolved, and awaiting it has no effect.
343
+ * @deprecated SharedSegmentSequence no longer supports partial loading.
344
+ * References to this promise may safely be deleted without affecting behavior.
345
+ */
120
346
  get loaded(): Promise<void> {
121
- return this.loadedDeferred.promise;
347
+ return Promise.resolve();
122
348
  }
123
349
 
124
350
  /**
@@ -153,11 +379,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
153
379
  lastAnnotate.pos2 += r.segment.cachedLength;
154
380
  } else {
155
381
  ops.push(
156
- createAnnotateRangeOp(
157
- r.position,
158
- r.position + r.segment.cachedLength,
159
- props,
160
- ),
382
+ createAnnotateRangeOp(r.position, r.position + r.segment.cachedLength, props),
161
383
  );
162
384
  }
163
385
  break;
@@ -170,15 +392,10 @@ export abstract class SharedSegmentSequence<T extends ISegment>
170
392
  case MergeTreeDeltaType.REMOVE: {
171
393
  const lastRem = ops[ops.length - 1] as IMergeTreeRemoveMsg;
172
394
  if (lastRem?.pos1 === r.position) {
173
- assert(
174
- lastRem.pos2 !== undefined,
175
- 0x3ff /* pos2 should not be undefined here */,
176
- );
395
+ assert(lastRem.pos2 !== undefined, 0x3ff /* pos2 should not be undefined here */);
177
396
  lastRem.pos2 += r.segment.cachedLength;
178
397
  } else {
179
- ops.push(
180
- createRemoveRangeOp(r.position, r.position + r.segment.cachedLength),
181
- );
398
+ ops.push(createRemoveRangeOp(r.position, r.position + r.segment.cachedLength));
182
399
  }
183
400
  break;
184
401
  }
@@ -187,18 +404,10 @@ export abstract class SharedSegmentSequence<T extends ISegment>
187
404
  // eslint-disable-next-line import/no-deprecated
188
405
  const lastRem = ops[ops.length - 1] as IMergeTreeObliterateMsg;
189
406
  if (lastRem?.pos1 === r.position) {
190
- assert(
191
- lastRem.pos2 !== undefined,
192
- 0x874 /* pos2 should not be undefined here */,
193
- );
407
+ assert(lastRem.pos2 !== undefined, 0x874 /* pos2 should not be undefined here */);
194
408
  lastRem.pos2 += r.segment.cachedLength;
195
409
  } else {
196
- ops.push(
197
- createObliterateRangeOp(
198
- r.position,
199
- r.position + r.segment.cachedLength,
200
- ),
201
- );
410
+ ops.push(createObliterateRangeOp(r.position, r.position + r.segment.cachedLength));
202
411
  }
203
412
  break;
204
413
  }
@@ -245,20 +454,10 @@ export abstract class SharedSegmentSequence<T extends ISegment>
245
454
 
246
455
  // eslint-disable-next-line import/no-deprecated
247
456
  protected client: Client;
248
- /** `Deferred` that triggers once the object is loaded */
249
- protected loadedDeferred = new Deferred<void>();
250
- // cache out going ops created when partial loading
251
- // eslint-disable-next-line import/no-deprecated
252
- private readonly loadedDeferredOutgoingOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] =
253
- [];
254
- // cache incoming ops that arrive when partial loading
255
- private deferIncomingOps = true;
256
- private readonly loadedDeferredIncomingOps: ISequencedDocumentMessage[] = [];
257
-
258
457
  private messagesSinceMSNChange: ISequencedDocumentMessage[] = [];
259
458
  private readonly intervalCollections: IntervalCollectionMap<SequenceInterval>;
260
459
  constructor(
261
- private readonly dataStoreRuntime: IFluidDataStoreRuntime,
460
+ dataStoreRuntime: IFluidDataStoreRuntime,
262
461
  public id: string,
263
462
  attributes: IChannelAttributes,
264
463
  public readonly segmentFromSpec: (spec: IJSONSegment) => ISegment,
@@ -277,11 +476,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
277
476
  new LoggingError(reentrancyErrorMessage),
278
477
  );
279
478
  }
280
- });
281
-
282
- this.loadedDeferred.promise.catch((error) => {
283
- this.logger.sendErrorEvent({ eventName: "SequenceLoadFailed" }, error);
284
- });
479
+ });
285
480
 
286
481
  // eslint-disable-next-line import/no-deprecated
287
482
  this.client = new Client(
@@ -322,40 +517,19 @@ export abstract class SharedSegmentSequence<T extends ISegment>
322
517
  );
323
518
  }
324
519
 
325
- /**
326
- * @param start - The inclusive start of the range to remove
327
- * @param end - The exclusive end of the range to remove
328
- */
329
520
  public removeRange(start: number, end: number): void {
330
521
  this.guardReentrancy(() => this.client.removeRangeLocal(start, end));
331
522
  }
332
523
 
333
- /**
334
- * Obliterate is similar to remove, but differs in that segments concurrently
335
- * inserted into an obliterated range will also be removed
336
- *
337
- * @param start - The inclusive start of the range to obliterate
338
- * @param end - The exclusive end of the range to obliterate
339
- */
340
524
  public obliterateRange(start: number, end: number): void {
341
525
  this.guardReentrancy(() => this.client.obliterateRangeLocal(start, end));
342
526
  }
343
527
 
344
- /**
345
- * @deprecated The ability to create group ops will be removed in an upcoming
346
- * release, as group ops are redundant with the native batching capabilities
347
- * of the runtime
348
- */
349
528
  // eslint-disable-next-line import/no-deprecated
350
- public groupOperation(groupOp: IMergeTreeGroupMsg) {
529
+ public groupOperation(groupOp: IMergeTreeGroupMsg): void {
351
530
  this.guardReentrancy(() => this.client.localTransaction(groupOp));
352
531
  }
353
532
 
354
- /**
355
- * Finds the segment information (i.e. segment + offset) corresponding to a character position in the SharedString.
356
- * If the position is past the end of the string, `segment` and `offset` on the returned object may be undefined.
357
- * @param pos - Character position (index) into the current local view of the SharedString.
358
- */
359
533
  public getContainingSegment(pos: number): {
360
534
  segment: T | undefined;
361
535
  offset: number | undefined;
@@ -363,50 +537,29 @@ export abstract class SharedSegmentSequence<T extends ISegment>
363
537
  return this.client.getContainingSegment<T>(pos);
364
538
  }
365
539
 
366
- /**
367
- * Returns the length of the current sequence for the client
368
- */
369
- public getLength() {
540
+ public getLength(): number {
370
541
  return this.client.getLength();
371
542
  }
372
543
 
373
- /**
374
- * Returns the current position of a segment, and -1 if the segment
375
- * does not exist in this sequence
376
- * @param segment - The segment to get the position of
377
- */
378
544
  public getPosition(segment: ISegment): number {
379
545
  return this.client.getPosition(segment);
380
546
  }
381
547
 
382
- /**
383
- * Annotates the range with the provided properties
384
- *
385
- * @param start - The inclusive start position of the range to annotate
386
- * @param end - The exclusive end position of the range to annotate
387
- * @param props - The properties to annotate the range with
388
- *
389
- */
390
548
  public annotateRange(start: number, end: number, props: PropertySet): void {
391
549
  this.guardReentrancy(() => this.client.annotateRangeLocal(start, end, props));
392
550
  }
393
551
 
394
- public getPropertiesAtPosition(pos: number) {
552
+ public getPropertiesAtPosition(pos: number): PropertySet | undefined {
395
553
  return this.client.getPropertiesAtPosition(pos);
396
554
  }
397
555
 
398
- public getRangeExtentsOfPosition(pos: number) {
556
+ public getRangeExtentsOfPosition(pos: number): {
557
+ posStart: number | undefined;
558
+ posAfterEnd: number | undefined;
559
+ } {
399
560
  return this.client.getRangeExtentsOfPosition(pos);
400
561
  }
401
562
 
402
- /**
403
- * Creates a `LocalReferencePosition` on this SharedString. If the refType does not include
404
- * ReferenceType.Transient, the returned reference will be added to the localRefs on the provided segment.
405
- * @param segment - Segment to add the local reference on
406
- * @param offset - Offset on the segment at which to place the local reference
407
- * @param refType - ReferenceType for the created local reference
408
- * @param properties - PropertySet to place on the created local reference
409
- */
410
563
  public createLocalReferencePosition(
411
564
  segment: T,
412
565
  offset: number,
@@ -425,39 +578,16 @@ export abstract class SharedSegmentSequence<T extends ISegment>
425
578
  );
426
579
  }
427
580
 
428
- /**
429
- * Resolves a `ReferencePosition` into a character position using this client's perspective.
430
- *
431
- * Reference positions that point to a character that has been removed will
432
- * always return the position of the nearest non-removed character, regardless
433
- * of `ReferenceType`. To handle this case specifically, one may wish
434
- * to look at the segment returned by `ReferencePosition.getSegment`.
435
- */
436
581
  public localReferencePositionToPosition(lref: ReferencePosition): number {
437
582
  return this.client.localReferencePositionToPosition(lref);
438
583
  }
439
584
 
440
- /**
441
- * Removes a `LocalReferencePosition` from this SharedString.
442
- */
443
- public removeLocalReferencePosition(lref: LocalReferencePosition) {
585
+ public removeLocalReferencePosition(
586
+ lref: LocalReferencePosition,
587
+ ): LocalReferencePosition | undefined {
444
588
  return this.client.removeLocalReferencePosition(lref);
445
589
  }
446
590
 
447
- /**
448
- * Resolves a remote client's position against the local sequence
449
- * and returns the remote client's position relative to the local
450
- * sequence. The client ref seq must be above the minimum sequence number
451
- * or the return value will be undefined.
452
- * Generally this method is used in conjunction with signals which provide
453
- * point in time values for the below parameters, and is useful for things
454
- * like displaying user position. It should not be used with persisted values
455
- * as persisted values will quickly become invalid as the remoteClientRefSeq
456
- * moves below the minimum sequence number
457
- * @param remoteClientPosition - The remote client's position to resolve
458
- * @param remoteClientRefSeq - The reference sequence number of the remote client
459
- * @param remoteClientId - The client id of the remote client
460
- */
461
591
  public resolveRemoteClientPosition(
462
592
  remoteClientPosition: number,
463
593
  remoteClientRefSeq: number,
@@ -481,39 +611,13 @@ export abstract class SharedSegmentSequence<T extends ISegment>
481
611
  message.type === MergeTreeDeltaType.GROUP ? message.ops.length : 1,
482
612
  );
483
613
 
484
- // if loading isn't complete, we need to cache
485
- // local ops until loading is complete, and then
486
- // they will be present
487
- if (!this.loadedDeferred.isCompleted) {
488
- this.loadedDeferredOutgoingOps.push(metadata ? [message, metadata] : (message as any));
489
- } else {
490
- this.submitLocalMessage(message, metadata);
491
- }
614
+ this.submitLocalMessage(message, metadata);
492
615
  }
493
616
 
494
- /**
495
- * Given a position specified relative to a marker id, lookup the marker
496
- * and convert the position to a character position.
497
- * @param relativePos - Id of marker (may be indirect) and whether position is before or after marker.
498
- */
499
- public posFromRelativePos(relativePos: IRelativePosition) {
617
+ public posFromRelativePos(relativePos: IRelativePosition): number {
500
618
  return this.client.posFromRelativePos(relativePos);
501
619
  }
502
620
 
503
- /**
504
- * Walk the underlying segments of the sequence.
505
- * The walked segments may extend beyond the range if the segments cross the
506
- * ranges start or end boundaries.
507
- *
508
- * Set split range to true to ensure only segments within the range are walked.
509
- *
510
- * @param handler - The function to handle each segment. Traversal ends if
511
- * this function returns true.
512
- * @param start - Optional. The start of range walk.
513
- * @param end - Optional. The end of range walk
514
- * @param accum - Optional. An object that will be passed to the handler for accumulation
515
- * @param splitRange - Optional. Splits boundary segments on the range boundaries
516
- */
517
621
  public walkSegments<TClientData>(
518
622
  handler: ISegmentAction<TClientData>,
519
623
  start?: number,
@@ -524,52 +628,23 @@ export abstract class SharedSegmentSequence<T extends ISegment>
524
628
  this.client.walkSegments(handler, start, end, accum as TClientData, splitRange);
525
629
  }
526
630
 
527
- /**
528
- * @returns The most recent sequence number which has been acked by the server and processed by this
529
- * SharedSegmentSequence.
530
- */
531
- public getCurrentSeq() {
631
+ public getCurrentSeq(): number {
532
632
  return this.client.getCurrentSeq();
533
633
  }
534
634
 
535
- /**
536
- * Inserts a segment directly before a `ReferencePosition`.
537
- * @param refPos - The reference position to insert the segment at
538
- * @param segment - The segment to insert
539
- */
540
635
  public insertAtReferencePosition(pos: ReferencePosition, segment: T): void {
541
636
  this.guardReentrancy(() => this.client.insertAtReferencePositionLocal(pos, segment));
542
637
  }
543
- /**
544
- * Inserts a segment
545
- * @param start - The position to insert the segment at
546
- * @param spec - The segment to inserts spec
547
- */
638
+
548
639
  public insertFromSpec(pos: number, spec: IJSONSegment): void {
549
640
  const segment = this.segmentFromSpec(spec);
550
641
  this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
551
642
  }
552
643
 
553
- /**
554
- * Retrieves the interval collection keyed on `label`. If no such interval collection exists,
555
- * creates one.
556
- */
557
644
  public getIntervalCollection(label: string): IIntervalCollection<SequenceInterval> {
558
645
  return this.intervalCollections.get(label);
559
646
  }
560
647
 
561
- /**
562
- * @returns An iterable object that enumerates the IntervalCollection labels.
563
- *
564
- * @example
565
- *
566
- * ```typescript
567
- * const iter = this.getIntervalCollectionKeys();
568
- * for (key of iter)
569
- * const collection = this.getIntervalCollection(key);
570
- * ...
571
- * ```
572
- */
573
648
  public getIntervalCollectionLabels(): IterableIterator<string> {
574
649
  return this.intervalCollections.keys();
575
650
  }
@@ -689,47 +764,38 @@ export abstract class SharedSegmentSequence<T extends ISegment>
689
764
  this.serializer,
690
765
  );
691
766
 
692
- // setup a promise to process the
693
- // catch up ops, and finishing the loading process
694
- const loadCatchUpOps = catchupOpsP
695
- .then((msgs) => {
696
- msgs.forEach((m) => {
697
- const collabWindow = this.client.getCollabWindow();
698
- if (
699
- m.minimumSequenceNumber < collabWindow.minSeq ||
700
- m.referenceSequenceNumber < collabWindow.minSeq ||
701
- m.sequenceNumber <= collabWindow.minSeq ||
702
- // sequenceNumber could be the same if messages are part of a grouped batch
703
- m.sequenceNumber < collabWindow.currentSeq
704
- ) {
705
- throw new Error(
706
- `Invalid catchup operations in snapshot: ${JSON.stringify({
707
- op: {
708
- seq: m.sequenceNumber,
709
- minSeq: m.minimumSequenceNumber,
710
- refSeq: m.referenceSequenceNumber,
711
- },
712
- collabWindow: {
713
- seq: collabWindow.currentSeq,
714
- minSeq: collabWindow.minSeq,
715
- },
716
- })}`,
717
- );
718
- }
719
- this.processMergeTreeMsg(m);
720
- });
721
- this.loadFinished();
722
- })
723
- .catch((error) => {
724
- this.loadFinished(error);
725
- });
726
- if (this.dataStoreRuntime.options.sequenceInitializeFromHeaderOnly !== true) {
727
- // if we not doing partial load, await the catch up ops,
728
- // and the finalization of the load
729
- await loadCatchUpOps;
730
- }
767
+ // process the catch up ops, and finishing the loading process
768
+ (await catchupOpsP).forEach((m) => {
769
+ const collabWindow = this.client.getCollabWindow();
770
+ if (
771
+ m.minimumSequenceNumber < collabWindow.minSeq ||
772
+ m.referenceSequenceNumber < collabWindow.minSeq ||
773
+ m.sequenceNumber <= collabWindow.minSeq ||
774
+ // sequenceNumber could be the same if messages are part of a grouped batch
775
+ m.sequenceNumber < collabWindow.currentSeq
776
+ ) {
777
+ throw new Error(
778
+ `Invalid catchup operations in snapshot: ${JSON.stringify({
779
+ op: {
780
+ seq: m.sequenceNumber,
781
+ minSeq: m.minimumSequenceNumber,
782
+ refSeq: m.referenceSequenceNumber,
783
+ },
784
+ collabWindow: {
785
+ seq: collabWindow.currentSeq,
786
+ minSeq: collabWindow.minSeq,
787
+ },
788
+ })}`,
789
+ );
790
+ }
791
+ this.processMergeTreeMsg(m);
792
+ });
793
+
794
+ // Initialize the interval collections
795
+ this.initializeIntervalCollections();
731
796
  } catch (error) {
732
- this.loadFinished(error);
797
+ this.logger.sendErrorEvent({ eventName: "SequenceLoadFailed" }, error);
798
+ throw error;
733
799
  }
734
800
  }
735
801
 
@@ -753,27 +819,20 @@ export abstract class SharedSegmentSequence<T extends ISegment>
753
819
  // assert(recordedRefSeq <= message.referenceSequenceNumber, "RefSeq mismatch");
754
820
  }
755
821
 
756
- // if loading isn't complete, we need to cache all
757
- // incoming ops to be applied after loading is complete
758
- if (this.deferIncomingOps) {
759
- assert(!local, 0x072 /* "Unexpected local op when loading not finished" */);
760
- this.loadedDeferredIncomingOps.push(message);
761
- } else {
762
- assert(
763
- message.type === MessageType.Operation,
764
- 0x073 /* "Sequence message not operation" */,
765
- );
822
+ assert(
823
+ message.type === MessageType.Operation,
824
+ 0x073 /* "Sequence message not operation" */,
825
+ );
766
826
 
767
- const handled = this.intervalCollections.tryProcessMessage(
768
- message.contents as IMapOperation,
769
- local,
770
- message,
771
- localOpMetadata,
772
- );
827
+ const handled = this.intervalCollections.tryProcessMessage(
828
+ message.contents as IMapOperation,
829
+ local,
830
+ message,
831
+ localOpMetadata,
832
+ );
773
833
 
774
- if (!handled) {
775
- this.processMergeTreeMsg(message, local);
776
- }
834
+ if (!handled) {
835
+ this.processMergeTreeMsg(message, local);
777
836
  }
778
837
  }
779
838
 
@@ -793,7 +852,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
793
852
  */
794
853
  protected initializeLocalCore() {
795
854
  super.initializeLocalCore();
796
- this.loadFinished();
855
+ this.initializeIntervalCollections();
797
856
  }
798
857
 
799
858
  /**
@@ -806,11 +865,6 @@ export abstract class SharedSegmentSequence<T extends ISegment>
806
865
  }
807
866
 
808
867
  private summarizeMergeTree(serializer: IFluidSerializer): ISummaryTreeWithStats {
809
- // Are we fully loaded? If not, things will go south
810
- assert(
811
- this.loadedDeferred.isCompleted,
812
- 0x074 /* "Snapshot called when not fully loaded" */,
813
- );
814
868
  const minSeq = this.deltaManager.minimumSequenceNumber;
815
869
 
816
870
  this.processMinSequenceNumberChanged(minSeq);
@@ -883,35 +937,6 @@ export abstract class SharedSegmentSequence<T extends ISegment>
883
937
  }
884
938
  }
885
939
 
886
- private loadFinished(error?: any) {
887
- if (!this.loadedDeferred.isCompleted) {
888
- // Initialize the interval collections
889
- this.initializeIntervalCollections();
890
- if (error) {
891
- this.loadedDeferred.reject(error);
892
- throw error;
893
- } else {
894
- // it is important this series remains synchronous
895
- // first we stop deferring incoming ops, and apply then all
896
- this.deferIncomingOps = false;
897
- for (const message of this.loadedDeferredIncomingOps) {
898
- this.processCore(message, false, undefined);
899
- }
900
- this.loadedDeferredIncomingOps.length = 0;
901
-
902
- // then resolve the loaded promise
903
- // and resubmit all the outstanding ops, as the snapshot
904
- // is fully loaded, and all outstanding ops are applied
905
- this.loadedDeferred.resolve();
906
-
907
- for (const [messageContent, opMetadata] of this.loadedDeferredOutgoingOps) {
908
- this.reSubmitCore(messageContent, opMetadata);
909
- }
910
- this.loadedDeferredOutgoingOps.length = 0;
911
- }
912
- }
913
- }
914
-
915
940
  private initializeIntervalCollections() {
916
941
  // Listen and initialize new SharedIntervalCollections
917
942
  this.intervalCollections.eventEmitter.on(