@fluidframework/merge-tree 2.41.0 → 2.42.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 (69) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/client.d.ts +6 -3
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +71 -25
  5. package/dist/client.js.map +1 -1
  6. package/dist/constants.d.ts +5 -0
  7. package/dist/constants.d.ts.map +1 -1
  8. package/dist/constants.js +6 -1
  9. package/dist/constants.js.map +1 -1
  10. package/dist/mergeTree.js +1 -1
  11. package/dist/mergeTree.js.map +1 -1
  12. package/dist/perspective.d.ts +15 -0
  13. package/dist/perspective.d.ts.map +1 -1
  14. package/dist/perspective.js +25 -1
  15. package/dist/perspective.js.map +1 -1
  16. package/dist/stamps.d.ts +1 -0
  17. package/dist/stamps.d.ts.map +1 -1
  18. package/dist/stamps.js +5 -1
  19. package/dist/stamps.js.map +1 -1
  20. package/dist/test/client.applyMsg.spec.js +4 -4
  21. package/dist/test/client.applyMsg.spec.js.map +1 -1
  22. package/dist/test/client.applyStashedOpFarm.spec.d.ts.map +1 -1
  23. package/dist/test/client.applyStashedOpFarm.spec.js +3 -3
  24. package/dist/test/client.applyStashedOpFarm.spec.js.map +1 -1
  25. package/dist/test/client.reconnectFarm.spec.js +1 -1
  26. package/dist/test/client.reconnectFarm.spec.js.map +1 -1
  27. package/dist/test/client.searchForMarker.spec.js +2 -2
  28. package/dist/test/client.searchForMarker.spec.js.map +1 -1
  29. package/dist/test/clientTestHelper.js +1 -1
  30. package/dist/test/clientTestHelper.js.map +1 -1
  31. package/dist/test/resetPendingSegmentsToOp.spec.js +10 -10
  32. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  33. package/lib/client.d.ts +6 -3
  34. package/lib/client.d.ts.map +1 -1
  35. package/lib/client.js +73 -27
  36. package/lib/client.js.map +1 -1
  37. package/lib/constants.d.ts +5 -0
  38. package/lib/constants.d.ts.map +1 -1
  39. package/lib/constants.js +5 -0
  40. package/lib/constants.js.map +1 -1
  41. package/lib/mergeTree.js +1 -1
  42. package/lib/mergeTree.js.map +1 -1
  43. package/lib/perspective.d.ts +15 -0
  44. package/lib/perspective.d.ts.map +1 -1
  45. package/lib/perspective.js +23 -0
  46. package/lib/perspective.js.map +1 -1
  47. package/lib/stamps.d.ts +1 -0
  48. package/lib/stamps.d.ts.map +1 -1
  49. package/lib/stamps.js +4 -1
  50. package/lib/stamps.js.map +1 -1
  51. package/lib/test/client.applyMsg.spec.js +4 -4
  52. package/lib/test/client.applyMsg.spec.js.map +1 -1
  53. package/lib/test/client.applyStashedOpFarm.spec.d.ts.map +1 -1
  54. package/lib/test/client.applyStashedOpFarm.spec.js +3 -3
  55. package/lib/test/client.applyStashedOpFarm.spec.js.map +1 -1
  56. package/lib/test/client.reconnectFarm.spec.js +1 -1
  57. package/lib/test/client.reconnectFarm.spec.js.map +1 -1
  58. package/lib/test/client.searchForMarker.spec.js +2 -2
  59. package/lib/test/client.searchForMarker.spec.js.map +1 -1
  60. package/lib/test/clientTestHelper.js +1 -1
  61. package/lib/test/clientTestHelper.js.map +1 -1
  62. package/lib/test/resetPendingSegmentsToOp.spec.js +10 -10
  63. package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  64. package/package.json +16 -16
  65. package/src/client.ts +95 -30
  66. package/src/constants.ts +6 -0
  67. package/src/mergeTree.ts +1 -1
  68. package/src/perspective.ts +26 -0
  69. package/src/stamps.ts +9 -1
@@ -76,6 +76,21 @@ export declare class LocalReconnectingPerspective extends PerspectiveBase implem
76
76
  constructor(refSeq: number, clientId: number, localSeq: number);
77
77
  hasOccurred(stamp: OperationStamp): boolean;
78
78
  }
79
+ /**
80
+ * This perspective is used when rebasing obliterate endpoints to find the segment to slide to when squash is enabled.
81
+ *
82
+ * TODO:AB#39357: This class would not be necessary if obliterate rebasing occurred as resubmit was called rather than
83
+ * precomputed before segment normalization. It also adds more dependencies on all ops being resubmitted (the squash
84
+ * parameter coming from rebasing an obliterate does not necessarily align with an inserted segment), which is not
85
+ * fully correct.
86
+ */
87
+ export declare class LocalSquashPerspective extends LocalReconnectingPerspective {
88
+ readonly refSeq: number;
89
+ readonly clientId: number;
90
+ readonly localSeq: number;
91
+ constructor(refSeq: number, clientId: number, localSeq: number);
92
+ isSegmentPresent(seg: ISegment): boolean;
93
+ }
79
94
  /**
80
95
  * A perspective which includes edits which were either:
81
96
  * - acked and at or before some reference sequence number
@@ -1 +1 @@
1
- {"version":3,"file":"perspective.d.ts","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAExE;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC;IAE7C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC;CAC5C;AAED,uBAAe,eAAe;IAC7B,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;IAE7C,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO;CAW/C;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,eAAgB,YAAW,WAAW;aAE1D,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;gBADhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;IAK1B,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAKlD;AAED;;;;;;;GAOG;AACH,qBAAa,4BAA6B,SAAQ,eAAgB,YAAW,WAAW;aAEtE,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,MAAM;gBAFhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAK1B,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAMlD;AAED;;;;;;GAMG;AACH,wBAAgB,kCAAkC,CACjD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACd,WAAW,CAEb;AAED;;;;;;;GAOG;AACH,qBAAa,uBAAwB,SAAQ,eAAgB,YAAW,WAAW;aAG/C,QAAQ,EAAE,MAAM;IAFnD,SAAgB,MAAM,SAA2B;gBAEd,QAAQ,EAAE,MAAM;IAI5C,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;CAGnD;AAED;;;;;;;GAOG;AACH,qBAAa,2BAA4B,SAAQ,eAAgB,YAAW,WAAW;aAG1D,QAAQ,EAAE,MAAM;IAF5C,SAAgB,MAAM,SAA2B;gBAErB,QAAQ,EAAE,MAAM;IAIrC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAYlD;AAOD,eAAO,MAAM,0BAA0B,kBAGtC,CAAC"}
1
+ {"version":3,"file":"perspective.d.ts","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG5D,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAExE;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC;IAE7C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC;CAC5C;AAED,uBAAe,eAAe;IAC7B,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;IAE7C,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO;CAW/C;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,eAAgB,YAAW,WAAW;aAE1D,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;gBADhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM;IAK1B,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAKlD;AAED;;;;;;;GAOG;AACH,qBAAa,4BAA6B,SAAQ,eAAgB,YAAW,WAAW;aAEtE,MAAM,EAAE,MAAM;aACd,QAAQ,EAAE,MAAM;aAChB,QAAQ,EAAE,MAAM;gBAFhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAK1B,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAMlD;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,4BAA4B;IAEtE,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBAFhB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAKV,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO;CAOxD;AAED;;;;;;GAMG;AACH,wBAAgB,kCAAkC,CACjD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACd,WAAW,CAEb;AAED;;;;;;;GAOG;AACH,qBAAa,uBAAwB,SAAQ,eAAgB,YAAW,WAAW;aAG/C,QAAQ,EAAE,MAAM;IAFnD,SAAgB,MAAM,SAA2B;gBAEd,QAAQ,EAAE,MAAM;IAI5C,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO;CAGnD;AAED;;;;;;;GAOG;AACH,qBAAa,2BAA4B,SAAQ,eAAgB,YAAW,WAAW;aAG1D,QAAQ,EAAE,MAAM;IAF5C,SAAgB,MAAM,SAA2B;gBAErB,QAAQ,EAAE,MAAM;IAIrC,WAAW,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;CAYlD;AAOD,eAAO,MAAM,0BAA0B,kBAGtC,CAAC"}
@@ -27,7 +27,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
27
27
  return result;
28
28
  };
29
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.allAckedChangesPerspective = exports.RemoteObliteratePerspective = exports.LocalDefaultPerspective = exports.createLocalReconnectingPerspective = exports.LocalReconnectingPerspective = exports.PriorPerspective = void 0;
30
+ exports.allAckedChangesPerspective = exports.RemoteObliteratePerspective = exports.LocalDefaultPerspective = exports.createLocalReconnectingPerspective = exports.LocalSquashPerspective = exports.LocalReconnectingPerspective = exports.PriorPerspective = void 0;
31
31
  const constants_js_1 = require("./constants.js");
32
32
  const mergeTreeNodes_js_1 = require("./mergeTreeNodes.js");
33
33
  const segmentInfos_js_1 = require("./segmentInfos.js");
@@ -85,6 +85,30 @@ class LocalReconnectingPerspective extends PerspectiveBase {
85
85
  }
86
86
  }
87
87
  exports.LocalReconnectingPerspective = LocalReconnectingPerspective;
88
+ /**
89
+ * This perspective is used when rebasing obliterate endpoints to find the segment to slide to when squash is enabled.
90
+ *
91
+ * TODO:AB#39357: This class would not be necessary if obliterate rebasing occurred as resubmit was called rather than
92
+ * precomputed before segment normalization. It also adds more dependencies on all ops being resubmitted (the squash
93
+ * parameter coming from rebasing an obliterate does not necessarily align with an inserted segment), which is not
94
+ * fully correct.
95
+ */
96
+ class LocalSquashPerspective extends LocalReconnectingPerspective {
97
+ constructor(refSeq, clientId, localSeq) {
98
+ super(refSeq, clientId, localSeq);
99
+ this.refSeq = refSeq;
100
+ this.clientId = clientId;
101
+ this.localSeq = localSeq;
102
+ }
103
+ isSegmentPresent(seg) {
104
+ // Avoid sliding to segments whose insertion will be squashed.
105
+ if ((0, segmentInfos_js_1.isInserted)(seg) && opstampUtils.isLocal(seg.insert) && (0, segmentInfos_js_1.isRemoved)(seg)) {
106
+ return false;
107
+ }
108
+ return super.isSegmentPresent(seg);
109
+ }
110
+ }
111
+ exports.LocalSquashPerspective = LocalSquashPerspective;
88
112
  /**
89
113
  * A perspective which includes edits which were either:
90
114
  * - acked and at or before some reference sequence number
@@ -1 +1 @@
1
- {"version":3,"file":"perspective.js","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NonCollabClient } from \"./constants.js\";\nimport { seqLTE, type ISegment } from \"./mergeTreeNodes.js\";\nimport { isInserted, isRemoved } from \"./segmentInfos.js\";\nimport * as opstampUtils from \"./stamps.js\";\nimport type { OperationStamp, RemoveOperationStamp } from \"./stamps.js\";\n\n/**\n * A perspective which includes some subset of operations known to the local client.\n *\n * This helps the local client reason about the state of other clients when they issued an operation.\n * @internal\n */\nexport interface Perspective {\n\t/**\n\t * The sequence number last seen from this perspective. Same concept as `ISequencedDocumentMessage.referenceSequenceNumber`.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly refSeq: number;\n\n\t/**\n\t * The client id for this perspective.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly clientId: number;\n\n\t/**\n\t * When this is a local perspective, the local sequence number last seen from this perspective.\n\t *\n\t * Perspectives with defined `localSeq` values are useful in reconnection flows, where the local client may need to resend some\n\t * of its ops after rederiving their new equivalents.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly localSeq?: number;\n\n\t/**\n\t * @returns Whether the segment is present (visible) from this perspective\n\t */\n\tisSegmentPresent(segment: ISegment): boolean;\n\n\t/**\n\t * @returns Whether this perspective has seen the given operation.\n\t */\n\thasOccurred(stamp: OperationStamp): boolean;\n}\n\nabstract class PerspectiveBase {\n\tabstract hasOccurred(stamp: OperationStamp): boolean;\n\n\tpublic isSegmentPresent(seg: ISegment): boolean {\n\t\tif (isInserted(seg) && !this.hasOccurred(seg.insert)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (isRemoved(seg) && seg.removes.some((remove) => this.hasOccurred(remove))) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\n/**\n * A perspective which includes edits at or before some reference sequence number alongside all edits from some particular client.\n *\n * @remarks\n * This works for both the local client as well as remote clients since refSeq-based checks disallow unacked edits, but the clientId check\n * catches unacked edits from the local client.\n */\nexport class PriorPerspective extends PerspectiveBase implements Perspective {\n\tpublic constructor(\n\t\tpublic readonly refSeq: number,\n\t\tpublic readonly clientId: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\tconst predatesViaRefSeq = seqLTE(stamp.seq, this.refSeq);\n\t\tconst predatesViaSameClient = stamp.clientId === this.clientId;\n\t\treturn predatesViaRefSeq || predatesViaSameClient;\n\t}\n}\n\n/**\n * A perspective which includes edits which were either:\n * - acked and at or before some reference sequence number\n * - unacked, but at or before some local sequence number\n *\n * This is a useful perspective when the local client is in the process of reconnecting, since it must\n * rederive positions for unacked ops while only considering a portion of its own edits as having been applied.\n */\nexport class LocalReconnectingPerspective extends PerspectiveBase implements Perspective {\n\tpublic constructor(\n\t\tpublic readonly refSeq: number,\n\t\tpublic readonly clientId: number,\n\t\tpublic readonly localSeq: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\tconst predatesViaRefSeq = seqLTE(stamp.seq, this.refSeq);\n\t\tconst predatesViaLocalSeq =\n\t\t\tstamp.localSeq !== undefined && stamp.localSeq <= this.localSeq;\n\t\treturn predatesViaRefSeq || predatesViaLocalSeq;\n\t}\n}\n\n/**\n * A perspective which includes edits which were either:\n * - acked and at or before some reference sequence number\n * - unacked, but at or before some local sequence number\n *\n * @internal\n */\nexport function createLocalReconnectingPerspective(\n\trefSeq: number,\n\tclientId: number,\n\tlocalSeq: number,\n): Perspective {\n\treturn new LocalReconnectingPerspective(refSeq, clientId, localSeq);\n}\n\n/**\n * A perspective which includes all known edits.\n *\n * This is the perspective that the application sees.\n * @remarks\n * This can be represented using {@link PriorPerspective} with a refSeq of `Number.MAX_SAFE_INTEGER`, but having an explicit\n * variant of this perspective renders extra refSeq checks unnecessary and is a bit easier to read.\n */\nexport class LocalDefaultPerspective extends PerspectiveBase implements Perspective {\n\tpublic readonly refSeq = Number.MAX_SAFE_INTEGER;\n\n\tpublic constructor(public readonly clientId: number) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(_stamp: OperationStamp): boolean {\n\t\treturn true;\n\t}\n}\n\n/**\n * A perspective dictating whether segments are 'visible' to a remote obliterate operation.\n *\n * NOTE: Beware that partial lengths doesn't support this perspective, in the sense that consulting partial lengths' for the length of a block\n * can give different results than summing the lengths of present segments in that block.\n * This ends up not affecting the current obliterate implementation (which has some special casing in the mapRange calls it uses),\n * but use with caution.\n */\nexport class RemoteObliteratePerspective extends PerspectiveBase implements Perspective {\n\tpublic readonly refSeq = Number.MAX_SAFE_INTEGER;\n\n\tconstructor(public readonly clientId: number) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\t// Local-only removals are not visible to an obliterate operation, since this means the local removal was concurrent\n\t\t// to a remote obliterate and we may need to mark the segment appropriately to reflect this overlapping remove.\n\t\t// Every other type of operation is visible: obliterates do not affect segments that have already been removed and acked,\n\t\t// and they always affect segments within their range that have not been removed, even if those segments were inserted\n\t\t// after the obliterate's refSeq.\n\t\tif (isRemoveOperationStamp(stamp) && opstampUtils.isLocal(stamp)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\nfunction isRemoveOperationStamp(stamp: OperationStamp): stamp is RemoveOperationStamp {\n\tconst { type } = stamp as unknown as RemoveOperationStamp;\n\treturn type === \"setRemove\" || type === \"sliceRemove\";\n}\n\nexport const allAckedChangesPerspective = new PriorPerspective(\n\tNumber.MAX_SAFE_INTEGER,\n\tNonCollabClient,\n);\n"]}
1
+ {"version":3,"file":"perspective.js","sourceRoot":"","sources":["../src/perspective.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NonCollabClient } from \"./constants.js\";\nimport { seqLTE, type ISegment } from \"./mergeTreeNodes.js\";\nimport { isInserted, isRemoved } from \"./segmentInfos.js\";\nimport * as opstampUtils from \"./stamps.js\";\nimport type { OperationStamp, RemoveOperationStamp } from \"./stamps.js\";\n\n/**\n * A perspective which includes some subset of operations known to the local client.\n *\n * This helps the local client reason about the state of other clients when they issued an operation.\n * @internal\n */\nexport interface Perspective {\n\t/**\n\t * The sequence number last seen from this perspective. Same concept as `ISequencedDocumentMessage.referenceSequenceNumber`.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly refSeq: number;\n\n\t/**\n\t * The client id for this perspective.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly clientId: number;\n\n\t/**\n\t * When this is a local perspective, the local sequence number last seen from this perspective.\n\t *\n\t * Perspectives with defined `localSeq` values are useful in reconnection flows, where the local client may need to resend some\n\t * of its ops after rederiving their new equivalents.\n\t * @privateRemarks\n\t * This currently allows inter-operation between MergeTree methods and the partial lengths implementation, which still depends\n\t * on the (refSeq, clientId, localSeq?) representation of perspectives.\n\t */\n\treadonly localSeq?: number;\n\n\t/**\n\t * @returns Whether the segment is present (visible) from this perspective\n\t */\n\tisSegmentPresent(segment: ISegment): boolean;\n\n\t/**\n\t * @returns Whether this perspective has seen the given operation.\n\t */\n\thasOccurred(stamp: OperationStamp): boolean;\n}\n\nabstract class PerspectiveBase {\n\tabstract hasOccurred(stamp: OperationStamp): boolean;\n\n\tpublic isSegmentPresent(seg: ISegment): boolean {\n\t\tif (isInserted(seg) && !this.hasOccurred(seg.insert)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (isRemoved(seg) && seg.removes.some((remove) => this.hasOccurred(remove))) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\n/**\n * A perspective which includes edits at or before some reference sequence number alongside all edits from some particular client.\n *\n * @remarks\n * This works for both the local client as well as remote clients since refSeq-based checks disallow unacked edits, but the clientId check\n * catches unacked edits from the local client.\n */\nexport class PriorPerspective extends PerspectiveBase implements Perspective {\n\tpublic constructor(\n\t\tpublic readonly refSeq: number,\n\t\tpublic readonly clientId: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\tconst predatesViaRefSeq = seqLTE(stamp.seq, this.refSeq);\n\t\tconst predatesViaSameClient = stamp.clientId === this.clientId;\n\t\treturn predatesViaRefSeq || predatesViaSameClient;\n\t}\n}\n\n/**\n * A perspective which includes edits which were either:\n * - acked and at or before some reference sequence number\n * - unacked, but at or before some local sequence number\n *\n * This is a useful perspective when the local client is in the process of reconnecting, since it must\n * rederive positions for unacked ops while only considering a portion of its own edits as having been applied.\n */\nexport class LocalReconnectingPerspective extends PerspectiveBase implements Perspective {\n\tpublic constructor(\n\t\tpublic readonly refSeq: number,\n\t\tpublic readonly clientId: number,\n\t\tpublic readonly localSeq: number,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\tconst predatesViaRefSeq = seqLTE(stamp.seq, this.refSeq);\n\t\tconst predatesViaLocalSeq =\n\t\t\tstamp.localSeq !== undefined && stamp.localSeq <= this.localSeq;\n\t\treturn predatesViaRefSeq || predatesViaLocalSeq;\n\t}\n}\n\n/**\n * This perspective is used when rebasing obliterate endpoints to find the segment to slide to when squash is enabled.\n *\n * TODO:AB#39357: This class would not be necessary if obliterate rebasing occurred as resubmit was called rather than\n * precomputed before segment normalization. It also adds more dependencies on all ops being resubmitted (the squash\n * parameter coming from rebasing an obliterate does not necessarily align with an inserted segment), which is not\n * fully correct.\n */\nexport class LocalSquashPerspective extends LocalReconnectingPerspective {\n\tpublic constructor(\n\t\treadonly refSeq: number,\n\t\treadonly clientId: number,\n\t\treadonly localSeq: number,\n\t) {\n\t\tsuper(refSeq, clientId, localSeq);\n\t}\n\n\tpublic override isSegmentPresent(seg: ISegment): boolean {\n\t\t// Avoid sliding to segments whose insertion will be squashed.\n\t\tif (isInserted(seg) && opstampUtils.isLocal(seg.insert) && isRemoved(seg)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn super.isSegmentPresent(seg);\n\t}\n}\n\n/**\n * A perspective which includes edits which were either:\n * - acked and at or before some reference sequence number\n * - unacked, but at or before some local sequence number\n *\n * @internal\n */\nexport function createLocalReconnectingPerspective(\n\trefSeq: number,\n\tclientId: number,\n\tlocalSeq: number,\n): Perspective {\n\treturn new LocalReconnectingPerspective(refSeq, clientId, localSeq);\n}\n\n/**\n * A perspective which includes all known edits.\n *\n * This is the perspective that the application sees.\n * @remarks\n * This can be represented using {@link PriorPerspective} with a refSeq of `Number.MAX_SAFE_INTEGER`, but having an explicit\n * variant of this perspective renders extra refSeq checks unnecessary and is a bit easier to read.\n */\nexport class LocalDefaultPerspective extends PerspectiveBase implements Perspective {\n\tpublic readonly refSeq = Number.MAX_SAFE_INTEGER;\n\n\tpublic constructor(public readonly clientId: number) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(_stamp: OperationStamp): boolean {\n\t\treturn true;\n\t}\n}\n\n/**\n * A perspective dictating whether segments are 'visible' to a remote obliterate operation.\n *\n * NOTE: Beware that partial lengths doesn't support this perspective, in the sense that consulting partial lengths' for the length of a block\n * can give different results than summing the lengths of present segments in that block.\n * This ends up not affecting the current obliterate implementation (which has some special casing in the mapRange calls it uses),\n * but use with caution.\n */\nexport class RemoteObliteratePerspective extends PerspectiveBase implements Perspective {\n\tpublic readonly refSeq = Number.MAX_SAFE_INTEGER;\n\n\tconstructor(public readonly clientId: number) {\n\t\tsuper();\n\t}\n\n\tpublic hasOccurred(stamp: OperationStamp): boolean {\n\t\t// Local-only removals are not visible to an obliterate operation, since this means the local removal was concurrent\n\t\t// to a remote obliterate and we may need to mark the segment appropriately to reflect this overlapping remove.\n\t\t// Every other type of operation is visible: obliterates do not affect segments that have already been removed and acked,\n\t\t// and they always affect segments within their range that have not been removed, even if those segments were inserted\n\t\t// after the obliterate's refSeq.\n\t\tif (isRemoveOperationStamp(stamp) && opstampUtils.isLocal(stamp)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\nfunction isRemoveOperationStamp(stamp: OperationStamp): stamp is RemoveOperationStamp {\n\tconst { type } = stamp as unknown as RemoveOperationStamp;\n\treturn type === \"setRemove\" || type === \"sliceRemove\";\n}\n\nexport const allAckedChangesPerspective = new PriorPerspective(\n\tNumber.MAX_SAFE_INTEGER,\n\tNonCollabClient,\n);\n"]}
package/dist/stamps.d.ts CHANGED
@@ -76,6 +76,7 @@ export declare function greaterThan(a: OperationStamp, b: OperationStamp): boole
76
76
  export declare function lte(a: OperationStamp, b: OperationStamp): boolean;
77
77
  export declare function equal(a: OperationStamp, b: OperationStamp): boolean;
78
78
  export declare function isLocal(a: OperationStamp): boolean;
79
+ export declare function isSquashedOp(a: OperationStamp): boolean;
79
80
  export declare function isAcked(a: OperationStamp): boolean;
80
81
  /**
81
82
  * Inserts a stamp into a sorted list of stamps in the correct (sorted) position.
@@ -1 +1 @@
1
- {"version":3,"file":"stamps.d.ts","sourceRoot":"","sources":["../src/stamps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC3D,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAwB,SAAQ,cAAc;IAC9D,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAChE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAAG,uBAAuB,GAAG,yBAAyB,CAAC;AAEvF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAWtE;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAWzE;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEnE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAElD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAclF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,CAEpE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAQpE"}
1
+ {"version":3,"file":"stamps.d.ts","sourceRoot":"","sources":["../src/stamps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,cAAc;IAC9B;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC3D,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,uBAAwB,SAAQ,cAAc;IAC9D,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,yBAA0B,SAAQ,cAAc;IAChE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,MAAM,oBAAoB,GAAG,uBAAuB,GAAG,yBAAyB,CAAC;AAEvF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAWtE;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAWzE;AAED,wBAAgB,GAAG,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAEnE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAElD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAEvD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAclF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,CAEpE;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CAQpE"}
package/dist/stamps.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.compare = exports.hasAnyAckedOperation = exports.spliceIntoList = exports.isAcked = exports.isLocal = exports.equal = exports.lte = exports.greaterThan = exports.gte = exports.lessThan = void 0;
7
+ exports.compare = exports.hasAnyAckedOperation = exports.spliceIntoList = exports.isAcked = exports.isSquashedOp = exports.isLocal = exports.equal = exports.lte = exports.greaterThan = exports.gte = exports.lessThan = void 0;
8
8
  const constants_js_1 = require("./constants.js");
9
9
  function lessThan(a, b) {
10
10
  if (a.seq === constants_js_1.UnassignedSequenceNumber) {
@@ -44,6 +44,10 @@ function isLocal(a) {
44
44
  return a.seq === constants_js_1.UnassignedSequenceNumber;
45
45
  }
46
46
  exports.isLocal = isLocal;
47
+ function isSquashedOp(a) {
48
+ return a.clientId === constants_js_1.SquashClient && a.seq === constants_js_1.UniversalSequenceNumber;
49
+ }
50
+ exports.isSquashedOp = isSquashedOp;
47
51
  function isAcked(a) {
48
52
  return a.seq !== constants_js_1.UnassignedSequenceNumber;
49
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stamps.js","sourceRoot":"","sources":["../src/stamps.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { UnassignedSequenceNumber } from \"./constants.js\";\n\n/**\n * A stamp that identifies provenance of an operation performed on the MergeTree.\n *\n * Stamps identify a point in time (`seq`/`localSeq`) as well as the source (`clientId`) for the operation.\n * This provides enough information to linearize all known applied operations: acked operations happen before\n * local+unacked ones, with acked operations ordered by their sequence numbers and local+unacked operations\n * ordered by their localSeq.\n *\n * By including `clientId`, it also provides enough information to resolve whether segments are visible\n * from alternative perspectives: a remote client will have seen all of its own previous operations as well as\n * those at or below the op's reference sequence number.\n *\n * @remarks - As the `readonly` identifies suggest, these stamps should be treated as immutable.\n * New operations applied to a merge-tree should create new stamps rather than modify existing ones (e.g. when\n * a change's ack happens).\n * @internal\n */\nexport interface OperationStamp {\n\t/**\n\t * The sequence number at which this operation was applied.\n\t */\n\treadonly seq: number;\n\n\t/**\n\t * Short clientId for the client that performed this operation.\n\t */\n\treadonly clientId: number;\n\n\t/**\n\t * Local seq at which this operation was applied.\n\t * This is defined if and only if the operation is pending an ack, i.e. `seq` is UnassignedSequenceNumber.\n\t *\n\t * @privateRemarks\n\t * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq.\n\t */\n\treadonly localSeq?: number;\n}\n\n/**\n * {@link OperationStamp} for an 'insert' operation.\n */\nexport interface InsertOperationStamp extends OperationStamp {\n\treadonly type: \"insert\";\n}\n\n/**\n * {@link OperationStamp} for a 'set remove' operation. This aligns with the `markRangeRemoved` API in MergeTree.\n *\n * @remarks The terminology here comes from the fact that the removal should affect only the *set* of nodes that were\n * specified at the time the local client issued the remove, and not any nodes that were inserted concurrently.\n *\n * Not using \"remove\" and \"obliterate\" here allows us to unambiguously use the term \"remove\" elsewhere in code to mean\n * \"removed from the tree, either by MergeTree.obliterateRange or MergeTree.removeRange\". This is convenient as the vast majority\n * of merge-tree code only cares about segment visibility and not the specific operation that caused a segment to be removed.\n */\nexport interface SetRemoveOperationStamp extends OperationStamp {\n\treadonly type: \"setRemove\";\n}\n\n/**\n * {@link OperationStamp} for a 'set remove' operation. This aligns with the `obliterateRange` API in MergeTree.\n *\n * @remarks The terminology here comes from the fact that the removal should affect the *slice* of nodes between the\n * start and end point specified by the local client, which includes any nodes that were inserted concurrently.\n *\n * Not using \"remove\" and \"obliterate\" here allows us to unambiguously use the term \"remove\" elsewhere in code to mean\n * \"removed from the tree, either by MergeTree.obliterateRange or MergeTree.removeRange\". This is convenient as the vast majority\n * of merge-tree code only cares about segment visibility and not the specific operation that caused a segment to be removed.\n */\nexport interface SliceRemoveOperationStamp extends OperationStamp {\n\treadonly type: \"sliceRemove\";\n}\n\nexport type RemoveOperationStamp = SetRemoveOperationStamp | SliceRemoveOperationStamp;\n\nexport function lessThan(a: OperationStamp, b: OperationStamp): boolean {\n\tif (a.seq === UnassignedSequenceNumber) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\treturn b.seq === UnassignedSequenceNumber && a.localSeq! < b.localSeq!;\n\t}\n\n\tif (b.seq === UnassignedSequenceNumber) {\n\t\treturn true;\n\t}\n\n\treturn a.seq < b.seq;\n}\n\nexport function gte(a: OperationStamp, b: OperationStamp): boolean {\n\treturn !lessThan(a, b);\n}\n\nexport function greaterThan(a: OperationStamp, b: OperationStamp): boolean {\n\tif (a.seq === UnassignedSequenceNumber) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\treturn b.seq !== UnassignedSequenceNumber || a.localSeq! > b.localSeq!;\n\t}\n\n\tif (b.seq === UnassignedSequenceNumber) {\n\t\treturn false;\n\t}\n\n\treturn a.seq > b.seq;\n}\n\nexport function lte(a: OperationStamp, b: OperationStamp): boolean {\n\treturn !greaterThan(a, b);\n}\n\nexport function equal(a: OperationStamp, b: OperationStamp): boolean {\n\treturn a.seq === b.seq && a.clientId === b.clientId && a.localSeq === b.localSeq;\n}\n\nexport function isLocal(a: OperationStamp): boolean {\n\treturn a.seq === UnassignedSequenceNumber;\n}\n\nexport function isAcked(a: OperationStamp): boolean {\n\treturn a.seq !== UnassignedSequenceNumber;\n}\n\n/**\n * Inserts a stamp into a sorted list of stamps in the correct (sorted) position.\n *\n * Beware that this uses Array.splice, thus requires asymptotics considerations.\n * If inserting a variable number of timestamps, consider just pushing them and sorting the list\n * after using {@link compare} instead.\n */\nexport function spliceIntoList(list: OperationStamp[], stamp: OperationStamp): void {\n\tif (isLocal(stamp) || list.length === 0) {\n\t\tlist.push(stamp);\n\t} else {\n\t\tfor (let i = list.length - 1; i >= 0; i--) {\n\t\t\tif (greaterThan(stamp, list[i])) {\n\t\t\t\tlist.splice(i + 1, 0, stamp);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Less than all stamps in the list: put it at the beginning.\n\t\tlist.unshift(stamp);\n\t}\n}\n\nexport function hasAnyAckedOperation(list: OperationStamp[]): boolean {\n\treturn list.some((ts) => isAcked(ts));\n}\n\nexport function compare(a: OperationStamp, b: OperationStamp): number {\n\tif (greaterThan(a, b)) {\n\t\treturn 1;\n\t} else if (lessThan(a, b)) {\n\t\treturn -1;\n\t} else {\n\t\treturn 0;\n\t}\n}\n"]}
1
+ {"version":3,"file":"stamps.js","sourceRoot":"","sources":["../src/stamps.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tSquashClient,\n\tUnassignedSequenceNumber,\n\tUniversalSequenceNumber,\n} from \"./constants.js\";\n\n/**\n * A stamp that identifies provenance of an operation performed on the MergeTree.\n *\n * Stamps identify a point in time (`seq`/`localSeq`) as well as the source (`clientId`) for the operation.\n * This provides enough information to linearize all known applied operations: acked operations happen before\n * local+unacked ones, with acked operations ordered by their sequence numbers and local+unacked operations\n * ordered by their localSeq.\n *\n * By including `clientId`, it also provides enough information to resolve whether segments are visible\n * from alternative perspectives: a remote client will have seen all of its own previous operations as well as\n * those at or below the op's reference sequence number.\n *\n * @remarks - As the `readonly` identifies suggest, these stamps should be treated as immutable.\n * New operations applied to a merge-tree should create new stamps rather than modify existing ones (e.g. when\n * a change's ack happens).\n * @internal\n */\nexport interface OperationStamp {\n\t/**\n\t * The sequence number at which this operation was applied.\n\t */\n\treadonly seq: number;\n\n\t/**\n\t * Short clientId for the client that performed this operation.\n\t */\n\treadonly clientId: number;\n\n\t/**\n\t * Local seq at which this operation was applied.\n\t * This is defined if and only if the operation is pending an ack, i.e. `seq` is UnassignedSequenceNumber.\n\t *\n\t * @privateRemarks\n\t * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq.\n\t */\n\treadonly localSeq?: number;\n}\n\n/**\n * {@link OperationStamp} for an 'insert' operation.\n */\nexport interface InsertOperationStamp extends OperationStamp {\n\treadonly type: \"insert\";\n}\n\n/**\n * {@link OperationStamp} for a 'set remove' operation. This aligns with the `markRangeRemoved` API in MergeTree.\n *\n * @remarks The terminology here comes from the fact that the removal should affect only the *set* of nodes that were\n * specified at the time the local client issued the remove, and not any nodes that were inserted concurrently.\n *\n * Not using \"remove\" and \"obliterate\" here allows us to unambiguously use the term \"remove\" elsewhere in code to mean\n * \"removed from the tree, either by MergeTree.obliterateRange or MergeTree.removeRange\". This is convenient as the vast majority\n * of merge-tree code only cares about segment visibility and not the specific operation that caused a segment to be removed.\n */\nexport interface SetRemoveOperationStamp extends OperationStamp {\n\treadonly type: \"setRemove\";\n}\n\n/**\n * {@link OperationStamp} for a 'set remove' operation. This aligns with the `obliterateRange` API in MergeTree.\n *\n * @remarks The terminology here comes from the fact that the removal should affect the *slice* of nodes between the\n * start and end point specified by the local client, which includes any nodes that were inserted concurrently.\n *\n * Not using \"remove\" and \"obliterate\" here allows us to unambiguously use the term \"remove\" elsewhere in code to mean\n * \"removed from the tree, either by MergeTree.obliterateRange or MergeTree.removeRange\". This is convenient as the vast majority\n * of merge-tree code only cares about segment visibility and not the specific operation that caused a segment to be removed.\n */\nexport interface SliceRemoveOperationStamp extends OperationStamp {\n\treadonly type: \"sliceRemove\";\n}\n\nexport type RemoveOperationStamp = SetRemoveOperationStamp | SliceRemoveOperationStamp;\n\nexport function lessThan(a: OperationStamp, b: OperationStamp): boolean {\n\tif (a.seq === UnassignedSequenceNumber) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\treturn b.seq === UnassignedSequenceNumber && a.localSeq! < b.localSeq!;\n\t}\n\n\tif (b.seq === UnassignedSequenceNumber) {\n\t\treturn true;\n\t}\n\n\treturn a.seq < b.seq;\n}\n\nexport function gte(a: OperationStamp, b: OperationStamp): boolean {\n\treturn !lessThan(a, b);\n}\n\nexport function greaterThan(a: OperationStamp, b: OperationStamp): boolean {\n\tif (a.seq === UnassignedSequenceNumber) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\treturn b.seq !== UnassignedSequenceNumber || a.localSeq! > b.localSeq!;\n\t}\n\n\tif (b.seq === UnassignedSequenceNumber) {\n\t\treturn false;\n\t}\n\n\treturn a.seq > b.seq;\n}\n\nexport function lte(a: OperationStamp, b: OperationStamp): boolean {\n\treturn !greaterThan(a, b);\n}\n\nexport function equal(a: OperationStamp, b: OperationStamp): boolean {\n\treturn a.seq === b.seq && a.clientId === b.clientId && a.localSeq === b.localSeq;\n}\n\nexport function isLocal(a: OperationStamp): boolean {\n\treturn a.seq === UnassignedSequenceNumber;\n}\n\nexport function isSquashedOp(a: OperationStamp): boolean {\n\treturn a.clientId === SquashClient && a.seq === UniversalSequenceNumber;\n}\n\nexport function isAcked(a: OperationStamp): boolean {\n\treturn a.seq !== UnassignedSequenceNumber;\n}\n\n/**\n * Inserts a stamp into a sorted list of stamps in the correct (sorted) position.\n *\n * Beware that this uses Array.splice, thus requires asymptotics considerations.\n * If inserting a variable number of timestamps, consider just pushing them and sorting the list\n * after using {@link compare} instead.\n */\nexport function spliceIntoList(list: OperationStamp[], stamp: OperationStamp): void {\n\tif (isLocal(stamp) || list.length === 0) {\n\t\tlist.push(stamp);\n\t} else {\n\t\tfor (let i = list.length - 1; i >= 0; i--) {\n\t\t\tif (greaterThan(stamp, list[i])) {\n\t\t\t\tlist.splice(i + 1, 0, stamp);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Less than all stamps in the list: put it at the beginning.\n\t\tlist.unshift(stamp);\n\t}\n}\n\nexport function hasAnyAckedOperation(list: OperationStamp[]): boolean {\n\treturn list.some((ts) => isAcked(ts));\n}\n\nexport function compare(a: OperationStamp, b: OperationStamp): number {\n\tif (greaterThan(a, b)) {\n\t\treturn 1;\n\t} else if (lessThan(a, b)) {\n\t\treturn -1;\n\t} else {\n\t\treturn 0;\n\t}\n}\n"]}
@@ -376,7 +376,7 @@ describe("client.applyMsg", () => {
376
376
  const seg = clientA.peekPendingSegmentGroups();
377
377
  const removeOp = clientB.makeOpMessage(clientB.removeRangeLocal(0, clientB.getLength()), ++seq);
378
378
  [clientA, clientB].map((c) => c.applyMsg(removeOp));
379
- const regeneratedOp = clientA.regeneratePendingOp(annotateOp, seg);
379
+ const regeneratedOp = clientA.regeneratePendingOp(annotateOp, seg, false);
380
380
  (0, node_assert_1.strict)(regeneratedOp.type === ops_js_1.MergeTreeDeltaType.GROUP);
381
381
  node_assert_1.strict.strictEqual(regeneratedOp.ops.length, 0);
382
382
  });
@@ -507,7 +507,7 @@ describe("client.applyMsg", () => {
507
507
  for (const op of clientOps.splice(0))
508
508
  clients.all[i].applyMsg(op);
509
509
  // rebase and resubmit disconnected client ops
510
- ops.push(clients.B.makeOpMessage(clients.B.regeneratePendingOp(bOp.op, bOp.sg), ++seq));
510
+ ops.push(clients.B.makeOpMessage(clients.B.regeneratePendingOp(bOp.op, bOp.sg, false), ++seq));
511
511
  const trackingGroup = new mergeTreeTracking_js_1.TrackingGroup();
512
512
  const trackedSegs = [];
513
513
  (0, mergeTreeNodeWalk_js_1.walkAllChildSegments)(clients.C.mergeTree.root, (seg) => {
@@ -516,7 +516,7 @@ describe("client.applyMsg", () => {
516
516
  });
517
517
  node_assert_1.strict.equal(beforeSlides, 0, "should be no slides");
518
518
  node_assert_1.strict.equal(afterSlides, 0, "should be no slides");
519
- ops.push(clients.C.makeOpMessage(clients.C.regeneratePendingOp(cOp.op, cOp.sg), ++seq));
519
+ ops.push(clients.C.makeOpMessage(clients.C.regeneratePendingOp(cOp.op, cOp.sg, false), ++seq));
520
520
  node_assert_1.strict.equal(beforeSlides, 1, "should be 1 slide");
521
521
  node_assert_1.strict.equal(afterSlides, 1, "should be 1 slide");
522
522
  for (const seg of trackedSegs) {
@@ -799,7 +799,7 @@ describe("client.applyMsg", () => {
799
799
  }
800
800
  node_assert_1.strict.equal(localClient.getCollabWindow().minSeq, 0);
801
801
  node_assert_1.strict.equal(remoteClient.getCollabWindow().minSeq, 16);
802
- ops.push(localClient.makeOpMessage(localClient.regeneratePendingOp(resubmittedOp, localClient.peekPendingSegmentGroups()),
802
+ ops.push(localClient.makeOpMessage(localClient.regeneratePendingOp(resubmittedOp, localClient.peekPendingSegmentGroups(), false),
803
803
  /* seq */ 18,
804
804
  /* refSeq */ 16, localUserLongId,
805
805
  /* minSeq */ 16));