@yorkie-js/react 0.6.27 → 0.6.29

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.
@@ -7088,6 +7088,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7088
7088
  * @generated from field: string client_id = 1;
7089
7089
  */
7090
7090
  __publicField(this, "clientId", "");
7091
+ /**
7092
+ * @generated from field: bool synchronous = 2;
7093
+ */
7094
+ __publicField(this, "synchronous", false);
7091
7095
  proto3.util.initPartial(data, this);
7092
7096
  }
7093
7097
  static fromBinary(bytes, options) {
@@ -7112,6 +7116,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7112
7116
  kind: "scalar",
7113
7117
  T: 9
7114
7118
  /* ScalarType.STRING */
7119
+ },
7120
+ {
7121
+ no: 2,
7122
+ name: "synchronous",
7123
+ kind: "scalar",
7124
+ T: 8
7125
+ /* ScalarType.BOOL */
7115
7126
  }
7116
7127
  ]));
7117
7128
  let DeactivateClientRequest = _DeactivateClientRequest;
@@ -8654,8 +8665,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
8654
8665
  }
8655
8666
  }
8656
8667
  /**
8657
- * eslint-disable-next-line jsdoc/require-jsdoc
8658
- * @internal
8668
+ * `[Symbol.iterator]` returns an iterator for the entries in this object.
8659
8669
  */
8660
8670
  *[Symbol.iterator]() {
8661
8671
  const keySet = /* @__PURE__ */ new Set();
@@ -10447,9 +10457,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
10447
10457
  * `findNextBeforeExecutedAt` returns the node by the given createdAt and
10448
10458
  * executedAt. It passes through nodes created after executedAt from the
10449
10459
  * given node and returns the next node.
10450
- * @param createdAt - created time
10451
- * @param executedAt - executed time
10452
- * @returns next node
10460
+ * @returns the next node of the given createdAt and executedAt
10453
10461
  */
10454
10462
  findNextBeforeExecutedAt(createdAt, executedAt) {
10455
10463
  let node = this.nodeMapByCreatedAt.get(createdAt.toIDString());
@@ -10785,8 +10793,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
10785
10793
  return this.elements.length;
10786
10794
  }
10787
10795
  /**
10788
- * eslint-disable-next-line jsdoc/require-jsdoc
10789
- * @internal
10796
+ * `[Symbol.iterator]` returns an iterator for the elements in this array.
10790
10797
  */
10791
10798
  *[Symbol.iterator]() {
10792
10799
  for (const node of this.elements) {
@@ -11689,8 +11696,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
11689
11696
  }
11690
11697
  /**
11691
11698
  * `edit` edits the given range with the given value and attributes.
11692
- *
11693
- * @internal
11694
11699
  */
11695
11700
  edit(range, content, editedAt, attributes, versionVector) {
11696
11701
  const crdtTextValue = content ? CRDTTextValue.create(content) : void 0;
@@ -11727,7 +11732,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
11727
11732
  * @param range - range of RGATreeSplitNode
11728
11733
  * @param attributes - style attributes
11729
11734
  * @param editedAt - edited time
11730
- * @internal
11731
11735
  */
11732
11736
  setStyle(range, attributes, editedAt, versionVector) {
11733
11737
  const diff = { data: 0, meta: 0 };
@@ -11881,8 +11885,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
11881
11885
  }
11882
11886
  /**
11883
11887
  * `getRGATreeSplit` returns rgaTreeSplit.
11884
- *
11885
- * @internal
11886
11888
  */
11887
11889
  getRGATreeSplit() {
11888
11890
  return this.rgaTreeSplit;
@@ -13995,8 +13997,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
13995
13997
  }
13996
13998
  /**
13997
13999
  * `toJSForTest` returns value with meta data for testing.
13998
- *
13999
- * @internal
14000
14000
  */
14001
14001
  toJSForTest() {
14002
14002
  return {
@@ -14007,8 +14007,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
14007
14007
  }
14008
14008
  /**
14009
14009
  * `toJSInfoForTest` returns detailed TreeNode information for use in Devtools.
14010
- *
14011
- * @internal
14012
14010
  */
14013
14011
  toJSInfoForTest() {
14014
14012
  const rootNode = this.indexTree.getRoot();
@@ -17562,11 +17560,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
17562
17560
  class Attachment {
17563
17561
  constructor(reconnectStreamDelay, doc, docID, syncMode, unsubscribeBroadcastEvent) {
17564
17562
  // TODO(hackerwins): Consider to changing the modifiers of the following properties to private.
17565
- __publicField(this, "reconnectStreamDelay");
17566
17563
  __publicField(this, "doc");
17567
17564
  __publicField(this, "docID");
17568
17565
  __publicField(this, "syncMode");
17569
17566
  __publicField(this, "remoteChangeEventReceived");
17567
+ __publicField(this, "reconnectStreamDelay");
17570
17568
  __publicField(this, "cancelled");
17571
17569
  __publicField(this, "watchStream");
17572
17570
  __publicField(this, "watchLoopTimerID");
@@ -17640,156 +17638,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
17640
17638
  this.watchLoopTimerID = void 0;
17641
17639
  }
17642
17640
  }
17643
- function validateYorkieRuleset(data, ruleset) {
17644
- const errors = [];
17645
- for (const rule of ruleset) {
17646
- const value = getValueByPath(data, rule.path);
17647
- const result = validateValue(value, rule);
17648
- if (!result.valid) {
17649
- for (const error of result.errors || []) {
17650
- errors.push(error);
17651
- }
17652
- }
17653
- }
17654
- return {
17655
- valid: errors.length === 0,
17656
- errors
17657
- };
17658
- }
17659
- function getValueByPath(obj, path) {
17660
- if (!path.startsWith("$")) {
17661
- throw new Error(`Path must start with $, got ${path}`);
17662
- }
17663
- const keys = path.split(".");
17664
- let current = obj;
17665
- for (let i = 1; i < keys.length; i++) {
17666
- const key = keys[i];
17667
- if (!(current instanceof CRDTObject)) {
17668
- return void 0;
17669
- }
17670
- current = current.get(key);
17671
- }
17672
- return current;
17673
- }
17674
- function validateValue(value, rule) {
17675
- switch (rule.type) {
17676
- case "string":
17677
- case "boolean":
17678
- case "integer":
17679
- case "double":
17680
- case "long":
17681
- case "date":
17682
- case "bytes":
17683
- case "null":
17684
- return validatePrimitiveValue(value, rule);
17685
- case "object":
17686
- if (!(value instanceof CRDTObject)) {
17687
- return {
17688
- valid: false,
17689
- errors: [
17690
- {
17691
- path: rule.path,
17692
- message: `expected object at path ${rule.path}`
17693
- }
17694
- ]
17695
- };
17696
- }
17697
- break;
17698
- case "array":
17699
- if (!(value instanceof CRDTArray)) {
17700
- return {
17701
- valid: false,
17702
- errors: [
17703
- {
17704
- path: rule.path,
17705
- message: `expected array at path ${rule.path}`
17706
- }
17707
- ]
17708
- };
17709
- }
17710
- break;
17711
- case "yorkie.Text":
17712
- if (!(value instanceof CRDTText)) {
17713
- return {
17714
- valid: false,
17715
- errors: [
17716
- {
17717
- path: rule.path,
17718
- message: `expected yorkie.Text at path ${rule.path}`
17719
- }
17720
- ]
17721
- };
17722
- }
17723
- break;
17724
- case "yorkie.Tree":
17725
- if (!(value instanceof CRDTTree)) {
17726
- return {
17727
- valid: false,
17728
- errors: [
17729
- {
17730
- path: rule.path,
17731
- message: `expected yorkie.Tree at path ${rule.path}`
17732
- }
17733
- ]
17734
- };
17735
- }
17736
- break;
17737
- case "yorkie.Counter":
17738
- if (!(value instanceof CRDTCounter)) {
17739
- return {
17740
- valid: false,
17741
- errors: [
17742
- {
17743
- path: rule.path,
17744
- message: `expected yorkie.Counter at path ${rule.path}`
17745
- }
17746
- ]
17747
- };
17748
- }
17749
- break;
17750
- default:
17751
- throw new Error(`Unknown rule type: ${rule.type}`);
17752
- }
17753
- return {
17754
- valid: true
17755
- };
17756
- }
17757
- function getPrimitiveType(type) {
17758
- switch (type) {
17759
- case "null":
17760
- return PrimitiveType.Null;
17761
- case "boolean":
17762
- return PrimitiveType.Boolean;
17763
- case "integer":
17764
- return PrimitiveType.Integer;
17765
- case "long":
17766
- return PrimitiveType.Long;
17767
- case "double":
17768
- return PrimitiveType.Double;
17769
- case "string":
17770
- return PrimitiveType.String;
17771
- case "bytes":
17772
- return PrimitiveType.Bytes;
17773
- case "date":
17774
- return PrimitiveType.Date;
17775
- default:
17776
- throw new Error(`Unknown primitive type: ${type}`);
17777
- }
17778
- }
17779
- function validatePrimitiveValue(value, rule) {
17780
- if (value instanceof Primitive && value.getType() === getPrimitiveType(rule.type)) {
17781
- return { valid: true };
17782
- }
17783
- return {
17784
- valid: false,
17785
- errors: [
17786
- {
17787
- path: rule.path,
17788
- message: `expected ${rule.type} at path ${rule.path}`
17789
- }
17790
- ]
17791
- };
17792
- }
17793
17641
  const Noop = () => {
17794
17642
  };
17795
17643
  class ObserverProxy {
@@ -18064,285 +17912,19 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
18064
17912
  this.root.acc(diff);
18065
17913
  }
18066
17914
  }
18067
- class CRDTRoot {
18068
- constructor(rootObject) {
18069
- /**
18070
- * `rootObject` is the root object of the document.
18071
- */
18072
- __publicField(this, "rootObject");
18073
- /**
18074
- * `elementPairMapByCreatedAt` is a hash table that maps the creation time of
18075
- * an element to the element itself and its parent.
18076
- */
18077
- __publicField(this, "elementPairMapByCreatedAt");
18078
- /**
18079
- * `gcElementSetByCreatedAt` is a hash set that contains the creation
18080
- * time of the removed element. It is used to find the removed element when
18081
- * executing garbage collection.
18082
- */
18083
- __publicField(this, "gcElementSetByCreatedAt");
18084
- /**
18085
- * `gcPairMap` is a hash table that maps the IDString of GCChild to the
18086
- * element itself and its parent.
18087
- */
18088
- __publicField(this, "gcPairMap");
18089
- /**
18090
- * `docSize` is a structure that represents the size of the document.
18091
- */
18092
- __publicField(this, "docSize");
18093
- this.rootObject = rootObject;
18094
- this.elementPairMapByCreatedAt = /* @__PURE__ */ new Map();
18095
- this.gcElementSetByCreatedAt = /* @__PURE__ */ new Set();
18096
- this.gcPairMap = /* @__PURE__ */ new Map();
18097
- this.docSize = { live: { data: 0, meta: 0 }, gc: { data: 0, meta: 0 } };
18098
- this.registerElement(rootObject, void 0);
18099
- rootObject.getDescendants((elem) => {
18100
- if (elem.getRemovedAt()) {
18101
- this.registerRemovedElement(elem);
18102
- }
18103
- if (elem instanceof CRDTText || elem instanceof CRDTTree) {
18104
- for (const pair of elem.getGCPairs()) {
18105
- this.registerGCPair(pair);
18106
- }
18107
- }
18108
- return false;
18109
- });
18110
- }
18111
- /**
18112
- * `create` creates a new instance of Root.
18113
- */
18114
- static create() {
18115
- return new CRDTRoot(CRDTObject.create(InitialTimeTicket));
18116
- }
18117
- /**
18118
- * `findByCreatedAt` returns the element of given creation time.
18119
- */
18120
- findByCreatedAt(createdAt) {
18121
- const pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
18122
- if (!pair) {
18123
- return;
18124
- }
18125
- return pair.element;
18126
- }
18127
- /**
18128
- * `findElementPairByCreatedAt` returns the element and parent pair
18129
- * of given creation time.
18130
- */
18131
- findElementPairByCreatedAt(createdAt) {
18132
- return this.elementPairMapByCreatedAt.get(createdAt.toIDString());
18133
- }
18134
- /**
18135
- * `createSubPaths` creates an array of the sub paths for the given element.
18136
- */
18137
- createSubPaths(createdAt) {
18138
- let pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
18139
- if (!pair) {
18140
- return [];
18141
- }
18142
- const subPaths = [];
18143
- while (pair.parent) {
18144
- const createdAt2 = pair.element.getCreatedAt();
18145
- const subPath = pair.parent.subPathOf(createdAt2);
18146
- if (subPath === void 0) {
18147
- throw new YorkieError(
18148
- Code.ErrInvalidArgument,
18149
- `cant find the given element: ${createdAt2.toIDString()}`
18150
- );
18151
- }
18152
- subPaths.unshift(subPath);
18153
- pair = this.elementPairMapByCreatedAt.get(
18154
- pair.parent.getCreatedAt().toIDString()
18155
- );
18156
- }
18157
- subPaths.unshift("$");
18158
- return subPaths;
18159
- }
18160
- /**
18161
- * `createPath` creates path of the given element.
18162
- */
18163
- createPath(createdAt) {
18164
- return this.createSubPaths(createdAt).join(".");
18165
- }
18166
- /**
18167
- * `registerElement` registers the given element and its descendants to hash table.
18168
- */
18169
- registerElement(element, parent) {
18170
- this.elementPairMapByCreatedAt.set(element.getCreatedAt().toIDString(), {
18171
- parent,
18172
- element
18173
- });
18174
- addDataSizes(this.docSize.live, element.getDataSize());
18175
- if (element instanceof CRDTContainer) {
18176
- element.getDescendants((elem, par) => {
18177
- this.elementPairMapByCreatedAt.set(elem.getCreatedAt().toIDString(), {
18178
- parent: par,
18179
- element: elem
18180
- });
18181
- addDataSizes(this.docSize.live, elem.getDataSize());
18182
- return false;
18183
- });
18184
- }
18185
- }
18186
- /**
18187
- * `deregisterElement` deregister the given element and its descendants from hash table.
18188
- */
18189
- deregisterElement(element) {
18190
- let count = 0;
18191
- const deregisterElementInternal = (elem) => {
18192
- const createdAt = elem.getCreatedAt().toIDString();
18193
- subDataSize(this.docSize.gc, elem.getDataSize());
18194
- this.elementPairMapByCreatedAt.delete(createdAt);
18195
- this.gcElementSetByCreatedAt.delete(createdAt);
18196
- count++;
18197
- };
18198
- deregisterElementInternal(element);
18199
- if (element instanceof CRDTContainer) {
18200
- element.getDescendants((e) => {
18201
- deregisterElementInternal(e);
18202
- return false;
18203
- });
18204
- }
18205
- return count;
18206
- }
18207
- /**
18208
- * `registerRemovedElement` registers the given element to the hash set.
18209
- */
18210
- registerRemovedElement(element) {
18211
- addDataSizes(this.docSize.gc, element.getDataSize());
18212
- subDataSize(this.docSize.live, element.getDataSize());
18213
- this.docSize.live.meta += TimeTicketSize;
18214
- this.gcElementSetByCreatedAt.add(element.getCreatedAt().toIDString());
18215
- }
18216
- /**
18217
- * `registerGCPair` registers the given pair to hash table.
18218
- */
18219
- registerGCPair(pair) {
18220
- const prev = this.gcPairMap.get(pair.child.toIDString());
18221
- if (prev) {
18222
- this.gcPairMap.delete(pair.child.toIDString());
18223
- return;
18224
- }
18225
- this.gcPairMap.set(pair.child.toIDString(), pair);
18226
- const size = this.gcPairMap.get(pair.child.toIDString()).child.getDataSize();
18227
- addDataSizes(this.docSize.gc, size);
18228
- subDataSize(this.docSize.live, size);
18229
- if (!(pair.child instanceof RHTNode)) {
18230
- this.docSize.live.meta += TimeTicketSize;
18231
- }
18232
- }
18233
- /**
18234
- * `getElementMapSize` returns the size of element map.
18235
- */
18236
- getElementMapSize() {
18237
- return this.elementPairMapByCreatedAt.size;
18238
- }
18239
- /**
18240
- * `getGarbageElementSetSize()` returns the size of removed element set.
18241
- */
18242
- getGarbageElementSetSize() {
18243
- const seen = /* @__PURE__ */ new Set();
18244
- for (const createdAt of this.gcElementSetByCreatedAt) {
18245
- seen.add(createdAt);
18246
- const pair = this.elementPairMapByCreatedAt.get(createdAt);
18247
- if (pair.element instanceof CRDTContainer) {
18248
- pair.element.getDescendants((el) => {
18249
- seen.add(el.getCreatedAt().toIDString());
18250
- return false;
18251
- });
18252
- }
18253
- }
18254
- return seen.size;
18255
- }
18256
- /**
18257
- * `getObject` returns root object.
18258
- */
18259
- getObject() {
18260
- return this.rootObject;
18261
- }
18262
- /**
18263
- * `getGarbageLen` returns length of nodes which can be garbage collected.
18264
- */
18265
- getGarbageLen() {
18266
- return this.getGarbageElementSetSize() + this.gcPairMap.size;
18267
- }
18268
- /**
18269
- * `getDocSize` returns the size of the document.
18270
- */
18271
- getDocSize() {
18272
- return this.docSize;
18273
- }
18274
- /**
18275
- * `deepcopy` copies itself deeply.
18276
- */
18277
- deepcopy() {
18278
- return new CRDTRoot(this.rootObject.deepcopy());
18279
- }
18280
- /**
18281
- * `garbageCollect` purges elements that were removed before the given time.
18282
- */
18283
- garbageCollect(minSyncedVersionVector) {
18284
- let count = 0;
18285
- for (const createdAt of this.gcElementSetByCreatedAt) {
18286
- const pair = this.elementPairMapByCreatedAt.get(createdAt);
18287
- const removedAt = pair.element.getRemovedAt();
18288
- if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
18289
- pair.parent.purge(pair.element);
18290
- count += this.deregisterElement(pair.element);
18291
- }
18292
- }
18293
- for (const [, pair] of this.gcPairMap) {
18294
- const removedAt = pair.child.getRemovedAt();
18295
- if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
18296
- pair.parent.purge(pair.child);
18297
- this.gcPairMap.delete(pair.child.toIDString());
18298
- count += 1;
18299
- }
18300
- }
18301
- return count;
18302
- }
18303
- /**
18304
- * `toJSON` returns the JSON encoding of this root object.
18305
- */
18306
- toJSON() {
18307
- return this.rootObject.toJSON();
18308
- }
18309
- /**
18310
- * `toSortedJSON` returns the sorted JSON encoding of this root object.
18311
- */
18312
- toSortedJSON() {
18313
- return this.rootObject.toSortedJSON();
18314
- }
18315
- /**
18316
- * `getStats` returns the current statistics of the root object.
18317
- * This includes counts of various types of elements and structural information.
18318
- */
18319
- getStats() {
18320
- return {
18321
- elements: this.getElementMapSize(),
18322
- gcPairs: this.gcPairMap.size,
18323
- gcElements: this.getGarbageElementSetSize()
18324
- };
18325
- }
18326
- /**
18327
- * `acc` accumulates the given DataSize to Live.
18328
- */
18329
- acc(diff) {
18330
- addDataSizes(this.docSize.live, diff);
18331
- }
18332
- }
18333
- function createJSONObject(context, target) {
18334
- const objectProxy = new ObjectProxy(context);
18335
- return new Proxy(target, objectProxy.getHandlers());
18336
- }
18337
- class ObjectProxy {
18338
- constructor(context) {
18339
- __publicField(this, "context");
18340
- __publicField(this, "handlers");
18341
- this.context = context;
18342
- this.handlers = {
18343
- set: (target, key, value) => {
18344
- if (logger.isEnabled(LogLevel.Trivial)) {
18345
- logger.trivial(`obj[${key}]=${JSON.stringify(value)}`);
17915
+ function createJSONObject(context, target) {
17916
+ const objectProxy = new ObjectProxy(context);
17917
+ return new Proxy(target, objectProxy.getHandlers());
17918
+ }
17919
+ class ObjectProxy {
17920
+ constructor(context) {
17921
+ __publicField(this, "context");
17922
+ __publicField(this, "handlers");
17923
+ this.context = context;
17924
+ this.handlers = {
17925
+ set: (target, key, value) => {
17926
+ if (logger.isEnabled(LogLevel.Trivial)) {
17927
+ logger.trivial(`obj[${key}]=${JSON.stringify(value)}`);
18346
17928
  }
18347
17929
  ObjectProxy.setInternal(context, target, key, value);
18348
17930
  return true;
@@ -19034,7 +18616,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19034
18616
  }
19035
18617
  /**
19036
18618
  * `initialize` initialize this text with context and internal text.
19037
- * @internal
19038
18619
  */
19039
18620
  initialize(context, text) {
19040
18621
  this.context = context;
@@ -19244,7 +18825,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19244
18825
  }
19245
18826
  /**
19246
18827
  * `toJSForTest` returns value with meta data for testing.
19247
- * @internal
19248
18828
  */
19249
18829
  toJSForTest() {
19250
18830
  if (!this.context || !this.text) {
@@ -19280,7 +18860,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19280
18860
  }
19281
18861
  /**
19282
18862
  * `initialize` initialize this text with context and internal text.
19283
- * @internal
19284
18863
  */
19285
18864
  initialize(context, counter) {
19286
18865
  this.valueType = counter.getValueType();
@@ -19296,7 +18875,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19296
18875
  }
19297
18876
  /**
19298
18877
  * `getValue` returns the value of this counter;
19299
- * @internal
19300
18878
  */
19301
18879
  getValue() {
19302
18880
  return this.value;
@@ -19332,7 +18910,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19332
18910
  }
19333
18911
  /**
19334
18912
  * `toJSForTest` returns value with meta data for testing.
19335
- * @internal
19336
18913
  */
19337
18914
  toJSForTest() {
19338
18915
  if (!this.context || !this.counter) {
@@ -19531,7 +19108,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19531
19108
  }
19532
19109
  /**
19533
19110
  * `initialize` initialize this tree with context and internal tree.
19534
- * @internal
19535
19111
  */
19536
19112
  initialize(context, tree) {
19537
19113
  this.context = context;
@@ -19942,7 +19518,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19942
19518
  }
19943
19519
  /**
19944
19520
  * `toJSForTest` returns value with meta data for testing.
19945
- * @internal
19946
19521
  */
19947
19522
  toJSForTest() {
19948
19523
  if (!this.context || !this.tree) {
@@ -19955,8 +19530,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
19955
19530
  }
19956
19531
  /**
19957
19532
  * `toJSInfoForTest` returns detailed TreeNode information for use in Devtools.
19958
- *
19959
- * @internal
19960
19533
  */
19961
19534
  toJSInfoForTest() {
19962
19535
  if (!this.context || !this.tree) {
@@ -20131,20 +19704,287 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20131
19704
  }
20132
19705
  return element;
20133
19706
  }
20134
- class Presence {
20135
- constructor(changeContext, presence) {
20136
- __publicField(this, "context");
20137
- __publicField(this, "presence");
20138
- this.context = changeContext;
20139
- this.presence = presence;
19707
+ class CRDTRoot {
19708
+ constructor(rootObject) {
19709
+ /**
19710
+ * `rootObject` is the root object of the document.
19711
+ */
19712
+ __publicField(this, "rootObject");
19713
+ /**
19714
+ * `elementPairMapByCreatedAt` is a hash table that maps the creation time of
19715
+ * an element to the element itself and its parent.
19716
+ */
19717
+ __publicField(this, "elementPairMapByCreatedAt");
19718
+ /**
19719
+ * `gcElementSetByCreatedAt` is a hash set that contains the creation
19720
+ * time of the removed element. It is used to find the removed element when
19721
+ * executing garbage collection.
19722
+ */
19723
+ __publicField(this, "gcElementSetByCreatedAt");
19724
+ /**
19725
+ * `gcPairMap` is a hash table that maps the IDString of GCChild to the
19726
+ * element itself and its parent.
19727
+ */
19728
+ __publicField(this, "gcPairMap");
19729
+ /**
19730
+ * `docSize` is a structure that represents the size of the document.
19731
+ */
19732
+ __publicField(this, "docSize");
19733
+ this.rootObject = rootObject;
19734
+ this.elementPairMapByCreatedAt = /* @__PURE__ */ new Map();
19735
+ this.gcElementSetByCreatedAt = /* @__PURE__ */ new Set();
19736
+ this.gcPairMap = /* @__PURE__ */ new Map();
19737
+ this.docSize = { live: { data: 0, meta: 0 }, gc: { data: 0, meta: 0 } };
19738
+ this.registerElement(rootObject, void 0);
19739
+ rootObject.getDescendants((elem) => {
19740
+ if (elem.getRemovedAt()) {
19741
+ this.registerRemovedElement(elem);
19742
+ }
19743
+ if (elem instanceof CRDTText || elem instanceof CRDTTree) {
19744
+ for (const pair of elem.getGCPairs()) {
19745
+ this.registerGCPair(pair);
19746
+ }
19747
+ }
19748
+ return false;
19749
+ });
20140
19750
  }
20141
19751
  /**
20142
- * `set` updates the presence based on the partial presence.
19752
+ * `create` creates a new instance of Root.
20143
19753
  */
20144
- set(presence, option) {
20145
- for (const key of Object.keys(presence)) {
20146
- this.presence[key] = presence[key];
20147
- }
19754
+ static create() {
19755
+ return new CRDTRoot(CRDTObject.create(InitialTimeTicket));
19756
+ }
19757
+ /**
19758
+ * `findByCreatedAt` returns the element of given creation time.
19759
+ */
19760
+ findByCreatedAt(createdAt) {
19761
+ const pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
19762
+ if (!pair) {
19763
+ return;
19764
+ }
19765
+ return pair.element;
19766
+ }
19767
+ /**
19768
+ * `findElementPairByCreatedAt` returns the element and parent pair
19769
+ * of given creation time.
19770
+ */
19771
+ findElementPairByCreatedAt(createdAt) {
19772
+ return this.elementPairMapByCreatedAt.get(createdAt.toIDString());
19773
+ }
19774
+ /**
19775
+ * `createSubPaths` creates an array of the sub paths for the given element.
19776
+ */
19777
+ createSubPaths(createdAt) {
19778
+ let pair = this.elementPairMapByCreatedAt.get(createdAt.toIDString());
19779
+ if (!pair) {
19780
+ return [];
19781
+ }
19782
+ const subPaths = [];
19783
+ while (pair.parent) {
19784
+ const createdAt2 = pair.element.getCreatedAt();
19785
+ const subPath = pair.parent.subPathOf(createdAt2);
19786
+ if (subPath === void 0) {
19787
+ throw new YorkieError(
19788
+ Code.ErrInvalidArgument,
19789
+ `cant find the given element: ${createdAt2.toIDString()}`
19790
+ );
19791
+ }
19792
+ subPaths.unshift(subPath);
19793
+ pair = this.elementPairMapByCreatedAt.get(
19794
+ pair.parent.getCreatedAt().toIDString()
19795
+ );
19796
+ }
19797
+ subPaths.unshift("$");
19798
+ return subPaths;
19799
+ }
19800
+ /**
19801
+ * `createPath` creates path of the given element.
19802
+ */
19803
+ createPath(createdAt) {
19804
+ return this.createSubPaths(createdAt).join(".");
19805
+ }
19806
+ /**
19807
+ * `registerElement` registers the given element and its descendants to hash table.
19808
+ */
19809
+ registerElement(element, parent) {
19810
+ this.elementPairMapByCreatedAt.set(element.getCreatedAt().toIDString(), {
19811
+ parent,
19812
+ element
19813
+ });
19814
+ addDataSizes(this.docSize.live, element.getDataSize());
19815
+ if (element instanceof CRDTContainer) {
19816
+ element.getDescendants((elem, par) => {
19817
+ this.elementPairMapByCreatedAt.set(elem.getCreatedAt().toIDString(), {
19818
+ parent: par,
19819
+ element: elem
19820
+ });
19821
+ addDataSizes(this.docSize.live, elem.getDataSize());
19822
+ return false;
19823
+ });
19824
+ }
19825
+ }
19826
+ /**
19827
+ * `deregisterElement` deregister the given element and its descendants from hash table.
19828
+ */
19829
+ deregisterElement(element) {
19830
+ let count = 0;
19831
+ const deregisterElementInternal = (elem) => {
19832
+ const createdAt = elem.getCreatedAt().toIDString();
19833
+ subDataSize(this.docSize.gc, elem.getDataSize());
19834
+ this.elementPairMapByCreatedAt.delete(createdAt);
19835
+ this.gcElementSetByCreatedAt.delete(createdAt);
19836
+ count++;
19837
+ };
19838
+ deregisterElementInternal(element);
19839
+ if (element instanceof CRDTContainer) {
19840
+ element.getDescendants((e) => {
19841
+ deregisterElementInternal(e);
19842
+ return false;
19843
+ });
19844
+ }
19845
+ return count;
19846
+ }
19847
+ /**
19848
+ * `registerRemovedElement` registers the given element to the hash set.
19849
+ */
19850
+ registerRemovedElement(element) {
19851
+ addDataSizes(this.docSize.gc, element.getDataSize());
19852
+ subDataSize(this.docSize.live, element.getDataSize());
19853
+ this.docSize.live.meta += TimeTicketSize;
19854
+ this.gcElementSetByCreatedAt.add(element.getCreatedAt().toIDString());
19855
+ }
19856
+ /**
19857
+ * `registerGCPair` registers the given pair to hash table.
19858
+ */
19859
+ registerGCPair(pair) {
19860
+ const prev = this.gcPairMap.get(pair.child.toIDString());
19861
+ if (prev) {
19862
+ this.gcPairMap.delete(pair.child.toIDString());
19863
+ return;
19864
+ }
19865
+ this.gcPairMap.set(pair.child.toIDString(), pair);
19866
+ const size = this.gcPairMap.get(pair.child.toIDString()).child.getDataSize();
19867
+ addDataSizes(this.docSize.gc, size);
19868
+ subDataSize(this.docSize.live, size);
19869
+ if (!(pair.child instanceof RHTNode)) {
19870
+ this.docSize.live.meta += TimeTicketSize;
19871
+ }
19872
+ }
19873
+ /**
19874
+ * `getElementMapSize` returns the size of element map.
19875
+ */
19876
+ getElementMapSize() {
19877
+ return this.elementPairMapByCreatedAt.size;
19878
+ }
19879
+ /**
19880
+ * `getGarbageElementSetSize()` returns the size of removed element set.
19881
+ */
19882
+ getGarbageElementSetSize() {
19883
+ const seen = /* @__PURE__ */ new Set();
19884
+ for (const createdAt of this.gcElementSetByCreatedAt) {
19885
+ seen.add(createdAt);
19886
+ const pair = this.elementPairMapByCreatedAt.get(createdAt);
19887
+ if (pair.element instanceof CRDTContainer) {
19888
+ pair.element.getDescendants((el) => {
19889
+ seen.add(el.getCreatedAt().toIDString());
19890
+ return false;
19891
+ });
19892
+ }
19893
+ }
19894
+ return seen.size;
19895
+ }
19896
+ /**
19897
+ * `getObject` returns root object.
19898
+ */
19899
+ getObject() {
19900
+ return this.rootObject;
19901
+ }
19902
+ /**
19903
+ * `getGarbageLen` returns length of nodes which can be garbage collected.
19904
+ */
19905
+ getGarbageLen() {
19906
+ return this.getGarbageElementSetSize() + this.gcPairMap.size;
19907
+ }
19908
+ /**
19909
+ * `getDocSize` returns the size of the document.
19910
+ */
19911
+ getDocSize() {
19912
+ return this.docSize;
19913
+ }
19914
+ /**
19915
+ * `deepcopy` copies itself deeply.
19916
+ */
19917
+ deepcopy() {
19918
+ return new CRDTRoot(this.rootObject.deepcopy());
19919
+ }
19920
+ /**
19921
+ * `garbageCollect` purges elements that were removed before the given time.
19922
+ */
19923
+ garbageCollect(minSyncedVersionVector) {
19924
+ let count = 0;
19925
+ for (const createdAt of this.gcElementSetByCreatedAt) {
19926
+ const pair = this.elementPairMapByCreatedAt.get(createdAt);
19927
+ const removedAt = pair.element.getRemovedAt();
19928
+ if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
19929
+ pair.parent.purge(pair.element);
19930
+ count += this.deregisterElement(pair.element);
19931
+ }
19932
+ }
19933
+ for (const [, pair] of this.gcPairMap) {
19934
+ const removedAt = pair.child.getRemovedAt();
19935
+ if (removedAt && (minSyncedVersionVector == null ? void 0 : minSyncedVersionVector.afterOrEqual(removedAt))) {
19936
+ pair.parent.purge(pair.child);
19937
+ subDataSize(this.docSize.gc, pair.child.getDataSize());
19938
+ this.gcPairMap.delete(pair.child.toIDString());
19939
+ count += 1;
19940
+ }
19941
+ }
19942
+ return count;
19943
+ }
19944
+ /**
19945
+ * `toJSON` returns the JSON encoding of this root object.
19946
+ */
19947
+ toJSON() {
19948
+ return this.rootObject.toJSON();
19949
+ }
19950
+ /**
19951
+ * `toSortedJSON` returns the sorted JSON encoding of this root object.
19952
+ */
19953
+ toSortedJSON() {
19954
+ return this.rootObject.toSortedJSON();
19955
+ }
19956
+ /**
19957
+ * `getStats` returns the current statistics of the root object.
19958
+ * This includes counts of various types of elements and structural information.
19959
+ */
19960
+ getStats() {
19961
+ return {
19962
+ elements: this.getElementMapSize(),
19963
+ gcPairs: this.gcPairMap.size,
19964
+ gcElements: this.getGarbageElementSetSize()
19965
+ };
19966
+ }
19967
+ /**
19968
+ * `acc` accumulates the given DataSize to Live.
19969
+ */
19970
+ acc(diff) {
19971
+ addDataSizes(this.docSize.live, diff);
19972
+ }
19973
+ }
19974
+ class Presence {
19975
+ constructor(changeContext, presence) {
19976
+ __publicField(this, "context");
19977
+ __publicField(this, "presence");
19978
+ this.context = changeContext;
19979
+ this.presence = presence;
19980
+ }
19981
+ /**
19982
+ * `set` updates the presence based on the partial presence.
19983
+ */
19984
+ set(presence, option) {
19985
+ for (const key of Object.keys(presence)) {
19986
+ this.presence[key] = presence[key];
19987
+ }
20148
19988
  this.context.setPresenceChange({
20149
19989
  type: PresenceChangeType.Put,
20150
19990
  presence: deepcopy(this.presence)
@@ -20159,7 +19999,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20159
19999
  }
20160
20000
  /**
20161
20001
  * `clear` clears the presence.
20162
- * @internal
20163
20002
  */
20164
20003
  clear() {
20165
20004
  this.presence = {};
@@ -20261,6 +20100,156 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20261
20100
  replace(this.redoStack);
20262
20101
  }
20263
20102
  }
20103
+ function validateYorkieRuleset(data, ruleset) {
20104
+ const errors = [];
20105
+ for (const rule of ruleset) {
20106
+ const value = getValueByPath(data, rule.path);
20107
+ const result = validateValue(value, rule);
20108
+ if (!result.valid) {
20109
+ for (const error of result.errors || []) {
20110
+ errors.push(error);
20111
+ }
20112
+ }
20113
+ }
20114
+ return {
20115
+ valid: errors.length === 0,
20116
+ errors
20117
+ };
20118
+ }
20119
+ function getValueByPath(obj, path) {
20120
+ if (!path.startsWith("$")) {
20121
+ throw new Error(`Path must start with $, got ${path}`);
20122
+ }
20123
+ const keys = path.split(".");
20124
+ let current = obj;
20125
+ for (let i = 1; i < keys.length; i++) {
20126
+ const key = keys[i];
20127
+ if (!(current instanceof CRDTObject)) {
20128
+ return void 0;
20129
+ }
20130
+ current = current.get(key);
20131
+ }
20132
+ return current;
20133
+ }
20134
+ function validateValue(value, rule) {
20135
+ switch (rule.type) {
20136
+ case "string":
20137
+ case "boolean":
20138
+ case "integer":
20139
+ case "double":
20140
+ case "long":
20141
+ case "date":
20142
+ case "bytes":
20143
+ case "null":
20144
+ return validatePrimitiveValue(value, rule);
20145
+ case "object":
20146
+ if (!(value instanceof CRDTObject)) {
20147
+ return {
20148
+ valid: false,
20149
+ errors: [
20150
+ {
20151
+ path: rule.path,
20152
+ message: `expected object at path ${rule.path}`
20153
+ }
20154
+ ]
20155
+ };
20156
+ }
20157
+ break;
20158
+ case "array":
20159
+ if (!(value instanceof CRDTArray)) {
20160
+ return {
20161
+ valid: false,
20162
+ errors: [
20163
+ {
20164
+ path: rule.path,
20165
+ message: `expected array at path ${rule.path}`
20166
+ }
20167
+ ]
20168
+ };
20169
+ }
20170
+ break;
20171
+ case "yorkie.Text":
20172
+ if (!(value instanceof CRDTText)) {
20173
+ return {
20174
+ valid: false,
20175
+ errors: [
20176
+ {
20177
+ path: rule.path,
20178
+ message: `expected yorkie.Text at path ${rule.path}`
20179
+ }
20180
+ ]
20181
+ };
20182
+ }
20183
+ break;
20184
+ case "yorkie.Tree":
20185
+ if (!(value instanceof CRDTTree)) {
20186
+ return {
20187
+ valid: false,
20188
+ errors: [
20189
+ {
20190
+ path: rule.path,
20191
+ message: `expected yorkie.Tree at path ${rule.path}`
20192
+ }
20193
+ ]
20194
+ };
20195
+ }
20196
+ break;
20197
+ case "yorkie.Counter":
20198
+ if (!(value instanceof CRDTCounter)) {
20199
+ return {
20200
+ valid: false,
20201
+ errors: [
20202
+ {
20203
+ path: rule.path,
20204
+ message: `expected yorkie.Counter at path ${rule.path}`
20205
+ }
20206
+ ]
20207
+ };
20208
+ }
20209
+ break;
20210
+ default:
20211
+ throw new Error(`Unknown rule type: ${rule.type}`);
20212
+ }
20213
+ return {
20214
+ valid: true
20215
+ };
20216
+ }
20217
+ function getPrimitiveType(type) {
20218
+ switch (type) {
20219
+ case "null":
20220
+ return PrimitiveType.Null;
20221
+ case "boolean":
20222
+ return PrimitiveType.Boolean;
20223
+ case "integer":
20224
+ return PrimitiveType.Integer;
20225
+ case "long":
20226
+ return PrimitiveType.Long;
20227
+ case "double":
20228
+ return PrimitiveType.Double;
20229
+ case "string":
20230
+ return PrimitiveType.String;
20231
+ case "bytes":
20232
+ return PrimitiveType.Bytes;
20233
+ case "date":
20234
+ return PrimitiveType.Date;
20235
+ default:
20236
+ throw new Error(`Unknown primitive type: ${type}`);
20237
+ }
20238
+ }
20239
+ function validatePrimitiveValue(value, rule) {
20240
+ if (value instanceof Primitive && value.getType() === getPrimitiveType(rule.type)) {
20241
+ return { valid: true };
20242
+ }
20243
+ return {
20244
+ valid: false,
20245
+ errors: [
20246
+ {
20247
+ path: rule.path,
20248
+ message: `expected ${rule.type} at path ${rule.path}`
20249
+ }
20250
+ ]
20251
+ };
20252
+ }
20264
20253
  const EventSourceDevPanel = "yorkie-devtools-panel";
20265
20254
  const EventSourceSDK = "yorkie-devtools-sdk";
20266
20255
  function isDocEventForReplay(event) {
@@ -20396,57 +20385,44 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20396
20385
  __publicField(this, "key");
20397
20386
  __publicField(this, "status");
20398
20387
  __publicField(this, "opts");
20388
+ __publicField(this, "maxSizeLimit");
20389
+ __publicField(this, "schemaRules");
20399
20390
  __publicField(this, "changeID");
20400
20391
  __publicField(this, "checkpoint");
20401
20392
  __publicField(this, "localChanges");
20402
- __publicField(this, "maxSizeLimit");
20403
- __publicField(this, "schemaRules");
20404
20393
  __publicField(this, "root");
20394
+ __publicField(this, "presences");
20405
20395
  __publicField(this, "clone");
20396
+ __publicField(this, "internalHistory");
20397
+ __publicField(this, "isUpdating");
20398
+ __publicField(this, "onlineClients");
20406
20399
  __publicField(this, "eventStream");
20407
20400
  __publicField(this, "eventStreamObserver");
20408
- /**
20409
- * `onlineClients` is a set of client IDs that are currently online.
20410
- */
20411
- __publicField(this, "onlineClients");
20412
- /**
20413
- * `presences` is a map of client IDs to their presence information.
20414
- */
20415
- __publicField(this, "presences");
20416
20401
  /**
20417
20402
  * `history` is exposed to the user to manage undo/redo operations.
20418
20403
  */
20419
20404
  __publicField(this, "history");
20420
- /**
20421
- * `internalHistory` is used to manage undo/redo operations internally.
20422
- */
20423
- __publicField(this, "internalHistory");
20424
- /**
20425
- * `isUpdating` is whether the document is updating by updater or not. It is
20426
- * used to prevent the updater from calling undo/redo.
20427
- */
20428
- __publicField(this, "isUpdating");
20429
- this.opts = opts || {};
20430
20405
  this.key = key;
20431
20406
  this.status = "detached";
20432
- this.root = CRDTRoot.create();
20407
+ this.opts = opts || {};
20408
+ this.maxSizeLimit = 0;
20409
+ this.schemaRules = [];
20433
20410
  this.changeID = InitialChangeID;
20434
20411
  this.checkpoint = InitialCheckpoint;
20435
20412
  this.localChanges = [];
20436
- this.maxSizeLimit = 0;
20437
- this.schemaRules = [];
20438
- this.eventStream = createObservable((observer) => {
20439
- this.eventStreamObserver = observer;
20440
- });
20441
- this.onlineClients = /* @__PURE__ */ new Set();
20413
+ this.root = CRDTRoot.create();
20442
20414
  this.presences = /* @__PURE__ */ new Map();
20443
- this.isUpdating = false;
20415
+ this.onlineClients = /* @__PURE__ */ new Set();
20444
20416
  this.internalHistory = new History();
20417
+ this.isUpdating = false;
20418
+ this.eventStream = createObservable(
20419
+ (observer) => this.eventStreamObserver = observer
20420
+ );
20445
20421
  this.history = {
20446
- canUndo: this.canUndo.bind(this),
20447
- canRedo: this.canRedo.bind(this),
20448
- undo: this.undo.bind(this),
20449
- redo: this.redo.bind(this)
20422
+ canUndo: () => this.internalHistory.hasUndo() && !this.isUpdating,
20423
+ canRedo: () => this.internalHistory.hasRedo() && !this.isUpdating,
20424
+ undo: () => this.executeUndoRedo(true),
20425
+ redo: () => this.executeUndoRedo(false)
20450
20426
  };
20451
20427
  setupDevtools(this);
20452
20428
  }
@@ -20460,7 +20436,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20460
20436
  }
20461
20437
  this.ensureClone();
20462
20438
  const actorID = this.changeID.getActorID();
20463
- const context = ChangeContext.create(
20439
+ const ctx = ChangeContext.create(
20464
20440
  this.changeID,
20465
20441
  this.clone.root,
20466
20442
  this.clone.presences.get(actorID) || {},
@@ -20468,29 +20444,23 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20468
20444
  );
20469
20445
  try {
20470
20446
  const proxy = createJSON(
20471
- context,
20447
+ ctx,
20472
20448
  this.clone.root.getObject()
20473
20449
  );
20474
20450
  if (!this.presences.has(actorID)) {
20475
20451
  this.clone.presences.set(actorID, {});
20476
20452
  }
20477
20453
  this.isUpdating = true;
20478
- updater(
20479
- proxy,
20480
- new Presence(context, this.clone.presences.get(actorID))
20481
- );
20454
+ updater(proxy, new Presence(ctx, this.clone.presences.get(actorID)));
20482
20455
  } catch (err) {
20483
20456
  this.clone = void 0;
20484
20457
  throw err;
20485
20458
  } finally {
20486
20459
  this.isUpdating = false;
20487
20460
  }
20488
- const schemaRules = this.getSchemaRules();
20489
- if (!context.isPresenceOnlyChange() && schemaRules.length > 0) {
20490
- const result = validateYorkieRuleset(
20491
- (_a2 = this.clone) == null ? void 0 : _a2.root.getObject(),
20492
- schemaRules
20493
- );
20461
+ const rules = this.getSchemaRules();
20462
+ if (!ctx.isPresenceOnlyChange() && rules.length) {
20463
+ const result = validateYorkieRuleset((_a2 = this.clone) == null ? void 0 : _a2.root.getObject(), rules);
20494
20464
  if (!result.valid) {
20495
20465
  this.clone = void 0;
20496
20466
  throw new YorkieError(
@@ -20500,18 +20470,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20500
20470
  }
20501
20471
  }
20502
20472
  const size = totalDocSize((_c2 = this.clone) == null ? void 0 : _c2.root.getDocSize());
20503
- if (!context.isPresenceOnlyChange() && this.maxSizeLimit > 0 && this.maxSizeLimit < size) {
20473
+ if (!ctx.isPresenceOnlyChange() && this.maxSizeLimit > 0 && this.maxSizeLimit < size) {
20504
20474
  this.clone = void 0;
20505
20475
  throw new YorkieError(
20506
20476
  Code.ErrDocumentSizeExceedsLimit,
20507
20477
  `document size exceeded: ${size} > ${this.maxSizeLimit}`
20508
20478
  );
20509
20479
  }
20510
- if (context.hasChange()) {
20480
+ if (ctx.hasChange()) {
20511
20481
  if (logger.isEnabled(LogLevel.Trivial)) {
20512
20482
  logger.trivial(`trying to update a local change: ${this.toJSON()}`);
20513
20483
  }
20514
- const change = context.toChange();
20484
+ const change = ctx.toChange();
20515
20485
  const { opInfos, reverseOps } = change.execute(
20516
20486
  this.root,
20517
20487
  this.presences,
@@ -20525,7 +20495,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20525
20495
  );
20526
20496
  }
20527
20497
  }
20528
- const reversePresence = context.getReversePresence();
20498
+ const reversePresence = ctx.getReversePresence();
20529
20499
  if (reversePresence) {
20530
20500
  reverseOps.push({
20531
20501
  type: "presence",
@@ -20533,15 +20503,15 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20533
20503
  });
20534
20504
  }
20535
20505
  this.localChanges.push(change);
20536
- if (reverseOps.length > 0) {
20506
+ if (reverseOps.length) {
20537
20507
  this.internalHistory.pushUndo(reverseOps);
20538
20508
  }
20539
- if (opInfos.length > 0) {
20509
+ if (opInfos.length) {
20540
20510
  this.internalHistory.clearRedo();
20541
20511
  }
20542
- this.changeID = context.getNextID();
20512
+ this.changeID = ctx.getNextID();
20543
20513
  const event = [];
20544
- if (opInfos.length > 0) {
20514
+ if (opInfos.length) {
20545
20515
  event.push({
20546
20516
  type: "local-change",
20547
20517
  source: OpSource.Local,
@@ -20763,32 +20733,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20763
20733
  * `publish` triggers an event in this document, which can be received by
20764
20734
  * callback functions from document.subscribe().
20765
20735
  */
20766
- publish(event) {
20736
+ publish(events) {
20767
20737
  if (this.eventStreamObserver) {
20768
- this.eventStreamObserver.next(event);
20769
- }
20770
- }
20771
- isSameElementOrChildOf(elem, parent) {
20772
- if (parent === elem) {
20773
- return true;
20774
- }
20775
- const nodePath = elem.split(".");
20776
- const targetPath = parent.split(".");
20777
- return targetPath.every((path, index) => path === nodePath[index]);
20778
- }
20779
- /**
20780
- * `removePushedLocalChanges` removes local changes that have been applied to
20781
- * the server from the local changes.
20782
- *
20783
- * @param clientSeq - client sequence number to remove local changes before it
20784
- */
20785
- removePushedLocalChanges(clientSeq) {
20786
- while (this.localChanges.length) {
20787
- const change = this.localChanges[0];
20788
- if (change.getID().getClientSeq() > clientSeq) {
20789
- break;
20790
- }
20791
- this.localChanges.shift();
20738
+ this.eventStreamObserver.next(events);
20792
20739
  }
20793
20740
  }
20794
20741
  /**
@@ -20796,13 +20743,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20796
20743
  * 1. Remove local changes applied to server.
20797
20744
  * 2. Update the checkpoint.
20798
20745
  * 3. Do Garbage collection.
20799
- *
20800
- * @param pack - change pack
20801
- * @internal
20802
20746
  */
20803
20747
  applyChangePack(pack) {
20804
- const hasSnapshot = pack.hasSnapshot();
20805
- if (hasSnapshot) {
20748
+ if (pack.hasSnapshot()) {
20806
20749
  this.applySnapshot(
20807
20750
  pack.getCheckpoint().getServerSeq(),
20808
20751
  pack.getVersionVector(),
@@ -20814,7 +20757,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20814
20757
  this.removePushedLocalChanges(pack.getCheckpoint().getClientSeq());
20815
20758
  }
20816
20759
  this.checkpoint = this.checkpoint.forward(pack.getCheckpoint());
20817
- if (!hasSnapshot) {
20760
+ if (!pack.hasSnapshot()) {
20818
20761
  this.garbageCollect(pack.getVersionVector());
20819
20762
  }
20820
20763
  if (pack.getIsRemoved()) {
@@ -20829,16 +20772,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20829
20772
  }
20830
20773
  /**
20831
20774
  * `getCheckpoint` returns the checkpoint of this document.
20832
- *
20833
- * @internal
20834
20775
  */
20835
20776
  getCheckpoint() {
20836
20777
  return this.checkpoint;
20837
20778
  }
20838
20779
  /**
20839
20780
  * `getChangeID` returns the change id of this document.
20840
- *
20841
- * @internal
20842
20781
  */
20843
20782
  getChangeID() {
20844
20783
  return this.changeID;
@@ -20851,8 +20790,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20851
20790
  }
20852
20791
  /**
20853
20792
  * `ensureClone` make a clone of root.
20854
- *
20855
- * @internal
20856
20793
  */
20857
20794
  ensureClone() {
20858
20795
  if (this.clone) {
@@ -20866,8 +20803,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20866
20803
  /**
20867
20804
  * `createChangePack` create change pack of the local changes to send to the
20868
20805
  * remote server.
20869
- *
20870
- * @internal
20871
20806
  */
20872
20807
  createChangePack() {
20873
20808
  const changes = Array.from(this.localChanges);
@@ -20883,8 +20818,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20883
20818
  /**
20884
20819
  * `setActor` sets actor into this document. This is also applied in the local
20885
20820
  * changes the document has.
20886
- *
20887
- * @internal
20888
20821
  */
20889
20822
  setActor(actorID) {
20890
20823
  for (const change of this.localChanges) {
@@ -20918,8 +20851,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20918
20851
  }
20919
20852
  /**
20920
20853
  * `getCloneRoot` returns clone object.
20921
- *
20922
- * @internal
20923
20854
  */
20924
20855
  getCloneRoot() {
20925
20856
  if (!this.clone) {
@@ -20932,12 +20863,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20932
20863
  */
20933
20864
  getRoot() {
20934
20865
  this.ensureClone();
20935
- const context = ChangeContext.create(
20866
+ const ctx = ChangeContext.create(
20936
20867
  this.changeID.next(),
20937
20868
  this.clone.root,
20938
20869
  this.clone.presences.get(this.changeID.getActorID()) || {}
20939
20870
  );
20940
- return createJSON(context, this.clone.root.getObject());
20871
+ return createJSON(ctx, this.clone.root.getObject());
20941
20872
  }
20942
20873
  /**
20943
20874
  * `getDocSize` returns the size of this document.
@@ -20971,8 +20902,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20971
20902
  }
20972
20903
  /**
20973
20904
  * `garbageCollect` purges elements that were removed before the given time.
20974
- *
20975
- * @internal
20976
20905
  */
20977
20906
  garbageCollect(minSyncedVersionVector) {
20978
20907
  if (this.opts.disableGC) {
@@ -20985,16 +20914,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
20985
20914
  }
20986
20915
  /**
20987
20916
  * `getRootObject` returns root object.
20988
- *
20989
- * @internal
20990
20917
  */
20991
20918
  getRootObject() {
20992
20919
  return this.root.getObject();
20993
20920
  }
20994
20921
  /**
20995
20922
  * `getGarbageLen` returns the length of elements should be purged.
20996
- *
20997
- * @internal
20998
20923
  */
20999
20924
  getGarbageLen() {
21000
20925
  return this.root.getGarbageLen();
@@ -21089,13 +21014,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21089
21014
  applyChange(change, source) {
21090
21015
  this.ensureClone();
21091
21016
  change.execute(this.clone.root, this.clone.presences, source);
21092
- const event = [];
21017
+ const events = [];
21093
21018
  const actorID = change.getID().getActorID();
21094
21019
  if (change.hasPresenceChange() && this.onlineClients.has(actorID)) {
21095
21020
  const presenceChange = change.getPresenceChange();
21096
21021
  switch (presenceChange.type) {
21097
21022
  case PresenceChangeType.Put:
21098
- event.push(
21023
+ events.push(
21099
21024
  this.presences.has(actorID) ? {
21100
21025
  type: "presence-changed",
21101
21026
  source,
@@ -21114,7 +21039,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21114
21039
  );
21115
21040
  break;
21116
21041
  case PresenceChangeType.Clear:
21117
- event.push({
21042
+ events.push({
21118
21043
  type: "unwatched",
21119
21044
  source: OpSource.Remote,
21120
21045
  value: {
@@ -21128,9 +21053,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21128
21053
  }
21129
21054
  const { opInfos } = change.execute(this.root, this.presences, source);
21130
21055
  this.changeID = this.changeID.syncClocks(change.getID());
21131
- if (opInfos.length > 0) {
21056
+ if (opInfos.length) {
21132
21057
  const rawChange = this.isEnableDevtools() ? change.toStruct() : void 0;
21133
- event.push(
21058
+ events.push(
21134
21059
  source === OpSource.Remote ? {
21135
21060
  type: "remote-change",
21136
21061
  source,
@@ -21156,8 +21081,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21156
21081
  }
21157
21082
  );
21158
21083
  }
21159
- if (event.length > 0) {
21160
- this.publish(event);
21084
+ if (events.length) {
21085
+ this.publish(events);
21161
21086
  }
21162
21087
  }
21163
21088
  /**
@@ -21185,14 +21110,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21185
21110
  }
21186
21111
  if (resp.body.case === "event") {
21187
21112
  const { type, publisher } = resp.body.value;
21188
- const event = [];
21113
+ const events = [];
21189
21114
  if (type === DocEventType$1.DOCUMENT_WATCHED) {
21190
21115
  if (this.onlineClients.has(publisher) && this.hasPresence(publisher)) {
21191
21116
  return;
21192
21117
  }
21193
21118
  this.addOnlineClient(publisher);
21194
21119
  if (this.hasPresence(publisher)) {
21195
- event.push({
21120
+ events.push({
21196
21121
  type: "watched",
21197
21122
  source: OpSource.Remote,
21198
21123
  value: {
@@ -21205,7 +21130,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21205
21130
  const presence = this.getPresence(publisher);
21206
21131
  this.removeOnlineClient(publisher);
21207
21132
  if (presence) {
21208
- event.push({
21133
+ events.push({
21209
21134
  type: "unwatched",
21210
21135
  source: OpSource.Remote,
21211
21136
  value: { clientID: publisher, presence }
@@ -21215,7 +21140,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21215
21140
  if (resp.body.value.body) {
21216
21141
  const { topic, payload } = resp.body.value.body;
21217
21142
  const decoder = new TextDecoder();
21218
- event.push({
21143
+ events.push({
21219
21144
  type: "broadcast",
21220
21145
  value: {
21221
21146
  clientID: publisher,
@@ -21225,8 +21150,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21225
21150
  });
21226
21151
  }
21227
21152
  }
21228
- if (event.length > 0) {
21229
- this.publish(event);
21153
+ if (events.length) {
21154
+ this.publish(events);
21230
21155
  }
21231
21156
  }
21232
21157
  }
@@ -21247,62 +21172,51 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21247
21172
  ]);
21248
21173
  }
21249
21174
  /**
21250
- * `applyDocEventForReplay` applies the given event into this document.
21175
+ * `applyDocEventsForReplay` applies the given events into this document.
21251
21176
  */
21252
- applyDocEventForReplay(event) {
21253
- if (event.type === "status-changed") {
21254
- this.applyStatus(event.value.status);
21255
- if (event.value.status === "attached") {
21256
- this.setActor(event.value.actorID);
21177
+ applyDocEventsForReplay(events) {
21178
+ for (const event of events) {
21179
+ if (event.type === "status-changed") {
21180
+ this.applyStatus(event.value.status);
21181
+ if (event.value.status === "attached") {
21182
+ this.setActor(event.value.actorID);
21183
+ }
21184
+ continue;
21257
21185
  }
21258
- return;
21259
- }
21260
- if (event.type === "snapshot") {
21261
- const { snapshot, serverSeq, snapshotVector } = event.value;
21262
- if (!snapshot) return;
21263
- this.applySnapshot(
21264
- BigInt(serverSeq),
21265
- converter.hexToVersionVector(snapshotVector),
21266
- converter.hexToBytes(snapshot)
21267
- );
21268
- return;
21269
- }
21270
- if (event.type === "local-change" || event.type === "remote-change") {
21271
- if (!event.rawChange) return;
21272
- const change = Change.fromStruct(event.rawChange);
21273
- this.applyChange(change, event.source);
21274
- }
21275
- if (event.type === "initialized") {
21276
- const onlineClients = /* @__PURE__ */ new Set();
21277
- for (const { clientID, presence } of event.value) {
21278
- onlineClients.add(clientID);
21186
+ if (event.type === "snapshot") {
21187
+ const { snapshot, serverSeq, snapshotVector } = event.value;
21188
+ if (!snapshot) continue;
21189
+ this.applySnapshot(
21190
+ BigInt(serverSeq),
21191
+ converter.hexToVersionVector(snapshotVector),
21192
+ converter.hexToBytes(snapshot)
21193
+ );
21194
+ continue;
21195
+ }
21196
+ if (event.type === "local-change" || event.type === "remote-change") {
21197
+ if (!event.rawChange) continue;
21198
+ const change = Change.fromStruct(event.rawChange);
21199
+ this.applyChange(change, event.source);
21200
+ }
21201
+ if (event.type === "initialized") {
21202
+ const onlineClients = /* @__PURE__ */ new Set();
21203
+ for (const { clientID, presence } of event.value) {
21204
+ onlineClients.add(clientID);
21205
+ this.presences.set(clientID, presence);
21206
+ }
21207
+ this.setOnlineClients(onlineClients);
21208
+ } else if (event.type === "watched") {
21209
+ const { clientID, presence } = event.value;
21210
+ this.addOnlineClient(clientID);
21211
+ this.presences.set(clientID, presence);
21212
+ } else if (event.type === "unwatched") {
21213
+ const { clientID } = event.value;
21214
+ this.removeOnlineClient(clientID);
21215
+ this.presences.delete(clientID);
21216
+ } else if (event.type === "presence-changed") {
21217
+ const { clientID, presence } = event.value;
21279
21218
  this.presences.set(clientID, presence);
21280
21219
  }
21281
- this.setOnlineClients(onlineClients);
21282
- return;
21283
- }
21284
- if (event.type === "watched") {
21285
- const { clientID, presence } = event.value;
21286
- this.addOnlineClient(clientID);
21287
- this.presences.set(clientID, presence);
21288
- return;
21289
- }
21290
- if (event.type === "unwatched") {
21291
- const { clientID } = event.value;
21292
- this.removeOnlineClient(clientID);
21293
- this.presences.delete(clientID);
21294
- }
21295
- if (event.type === "presence-changed") {
21296
- const { clientID, presence } = event.value;
21297
- this.presences.set(clientID, presence);
21298
- }
21299
- }
21300
- /**
21301
- * `applyDocEventsForReplay` applies the given events into this document.
21302
- */
21303
- applyDocEventsForReplay(event) {
21304
- for (const docEvent of event) {
21305
- this.applyDocEventForReplay(docEvent);
21306
21220
  }
21307
21221
  }
21308
21222
  /**
@@ -21315,51 +21229,41 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21315
21229
  `path must start with "$"`
21316
21230
  );
21317
21231
  }
21318
- const pathArr = path.split(".");
21319
- pathArr.shift();
21232
+ const paths = path.split(".");
21233
+ paths.shift();
21320
21234
  let value = this.getRoot();
21321
- for (const key of pathArr) {
21235
+ for (const key of paths) {
21322
21236
  value = value[key];
21323
- if (value === void 0) return void 0;
21237
+ if (!value) return void 0;
21324
21238
  }
21325
21239
  return value;
21326
21240
  }
21327
21241
  /**
21328
21242
  * `setOnlineClients` sets the given online client set.
21329
- *
21330
- * @internal
21331
21243
  */
21332
21244
  setOnlineClients(onlineClients) {
21333
21245
  this.onlineClients = onlineClients;
21334
21246
  }
21335
21247
  /**
21336
21248
  * `resetOnlineClients` resets the online client set.
21337
- *
21338
- * @internal
21339
21249
  */
21340
21250
  resetOnlineClients() {
21341
21251
  this.onlineClients = /* @__PURE__ */ new Set();
21342
21252
  }
21343
21253
  /**
21344
21254
  * `addOnlineClient` adds the given clientID into the online client set.
21345
- *
21346
- * @internal
21347
21255
  */
21348
21256
  addOnlineClient(clientID) {
21349
21257
  this.onlineClients.add(clientID);
21350
21258
  }
21351
21259
  /**
21352
21260
  * `removeOnlineClient` removes the clientID from the online client set.
21353
- *
21354
- * @internal
21355
21261
  */
21356
21262
  removeOnlineClient(clientID) {
21357
21263
  this.onlineClients.delete(clientID);
21358
21264
  }
21359
21265
  /**
21360
21266
  * `hasPresence` returns whether the given clientID has a presence or not.
21361
- *
21362
- * @internal
21363
21267
  */
21364
21268
  hasPresence(clientID) {
21365
21269
  return this.presences.has(clientID);
@@ -21374,6 +21278,22 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21374
21278
  const p = this.presences.get(this.changeID.getActorID());
21375
21279
  return p ? deepcopy(p) : {};
21376
21280
  }
21281
+ /**
21282
+ * `getOthersPresences` returns the presences of all other clients.
21283
+ */
21284
+ getOthersPresences() {
21285
+ const others = [];
21286
+ const myClientID = this.changeID.getActorID();
21287
+ for (const clientID of this.onlineClients) {
21288
+ if (clientID !== myClientID && this.presences.has(clientID)) {
21289
+ others.push({
21290
+ clientID,
21291
+ presence: deepcopy(this.presences.get(clientID))
21292
+ });
21293
+ }
21294
+ }
21295
+ return others;
21296
+ }
21377
21297
  /**
21378
21298
  * `getPresence` returns the presence of the given clientID.
21379
21299
  */
@@ -21385,16 +21305,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21385
21305
  const p = this.presences.get(clientID);
21386
21306
  return p ? deepcopy(p) : void 0;
21387
21307
  }
21388
- /**
21389
- * `getPresenceForTest` returns the presence of the given clientID
21390
- * regardless of whether the client is online or not.
21391
- *
21392
- * @internal
21393
- */
21394
- getPresenceForTest(clientID) {
21395
- const p = this.presences.get(clientID);
21396
- return p ? deepcopy(p) : void 0;
21397
- }
21398
21308
  /**
21399
21309
  * `getPresences` returns the presences of online clients.
21400
21310
  */
@@ -21414,10 +21324,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21414
21324
  }
21415
21325
  return presences;
21416
21326
  }
21327
+ /**
21328
+ * `getPresenceForTest` returns the presence of the given clientID
21329
+ * regardless of whether the client is online or not.
21330
+ */
21331
+ getPresenceForTest(clientID) {
21332
+ const p = this.presences.get(clientID);
21333
+ return p ? deepcopy(p) : void 0;
21334
+ }
21417
21335
  /**
21418
21336
  * `getSelfForTest` returns the client that has attached this document.
21419
- *
21420
- * @internal
21421
21337
  */
21422
21338
  getSelfForTest() {
21423
21339
  return {
@@ -21427,193 +21343,135 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21427
21343
  }
21428
21344
  /**
21429
21345
  * `getOthersForTest` returns all the other clients in online, sorted by clientID.
21430
- *
21431
- * @internal
21432
21346
  */
21433
21347
  getOthersForTest() {
21434
21348
  const myClientID = this.getChangeID().getActorID();
21435
21349
  return this.getPresences().filter((a) => a.clientID !== myClientID).sort((a, b) => a.clientID > b.clientID ? 1 : -1);
21436
21350
  }
21437
21351
  /**
21438
- * `canUndo` returns whether there are any operations to undo.
21352
+ * `getUndoStackForTest` returns the undo stack for test.
21439
21353
  */
21440
- canUndo() {
21441
- return this.internalHistory.hasUndo() && !this.isUpdating;
21354
+ getUndoStackForTest() {
21355
+ return this.internalHistory.getUndoStackForTest();
21442
21356
  }
21443
21357
  /**
21444
- * `canRedo` returns whether there are any operations to redo.
21358
+ * `getRedoStackForTest` returns the redo stack for test.
21445
21359
  */
21446
- canRedo() {
21447
- return this.internalHistory.hasRedo() && !this.isUpdating;
21360
+ getRedoStackForTest() {
21361
+ return this.internalHistory.getRedoStackForTest();
21448
21362
  }
21449
21363
  /**
21450
- * `undo` undoes the last operation executed by the current client.
21451
- * It does not impact operations made by other clients.
21364
+ * `broadcast` the payload to the given topic.
21452
21365
  */
21453
- undo() {
21454
- if (this.isUpdating) {
21455
- throw new YorkieError(
21456
- Code.ErrRefused,
21457
- "Undo is not allowed during an update"
21458
- );
21459
- }
21460
- const undoOps = this.internalHistory.popUndo();
21461
- if (undoOps === void 0) {
21462
- throw new YorkieError(
21463
- Code.ErrRefused,
21464
- "There is no operation to be undone"
21465
- );
21466
- }
21467
- this.ensureClone();
21468
- const context = ChangeContext.create(
21469
- this.changeID,
21470
- this.clone.root,
21471
- this.clone.presences.get(this.changeID.getActorID()) || {}
21472
- );
21473
- for (const undoOp of undoOps) {
21474
- if (!(undoOp instanceof Operation)) {
21475
- const presence = new Presence(
21476
- context,
21477
- deepcopy(this.clone.presences.get(this.changeID.getActorID()))
21478
- );
21479
- presence.set(undoOp.value, { addToHistory: true });
21480
- continue;
21481
- }
21482
- const ticket = context.issueTimeTicket();
21483
- undoOp.setExecutedAt(ticket);
21484
- if (undoOp instanceof ArraySetOperation) {
21485
- const prev = undoOp.getCreatedAt();
21486
- undoOp.getValue().setCreatedAt(ticket);
21487
- this.internalHistory.reconcileCreatedAt(prev, ticket);
21488
- } else if (undoOp instanceof AddOperation) {
21489
- const prev = undoOp.getValue().getCreatedAt();
21490
- undoOp.getValue().setCreatedAt(ticket);
21491
- this.internalHistory.reconcileCreatedAt(prev, ticket);
21366
+ broadcast(topic, payload, options) {
21367
+ this.publish([
21368
+ {
21369
+ type: "local-broadcast",
21370
+ value: { topic, payload },
21371
+ options
21492
21372
  }
21493
- context.push(undoOp);
21494
- }
21495
- const change = context.toChange();
21496
- change.execute(this.clone.root, this.clone.presences, OpSource.UndoRedo);
21497
- const { opInfos, reverseOps } = change.execute(
21498
- this.root,
21499
- this.presences,
21500
- OpSource.UndoRedo
21501
- );
21502
- const reversePresence = context.getReversePresence();
21503
- if (reversePresence) {
21504
- reverseOps.push({
21505
- type: "presence",
21506
- value: reversePresence
21507
- });
21508
- }
21509
- if (reverseOps.length > 0) {
21510
- this.internalHistory.pushRedo(reverseOps);
21511
- }
21512
- if (!change.hasPresenceChange() && opInfos.length === 0) {
21513
- return;
21514
- }
21515
- this.localChanges.push(change);
21516
- this.changeID = context.getNextID();
21517
- const actorID = this.changeID.getActorID();
21518
- const event = [];
21519
- if (opInfos.length > 0) {
21520
- event.push({
21521
- type: "local-change",
21522
- source: OpSource.UndoRedo,
21523
- value: {
21524
- message: change.getMessage() || "",
21525
- operations: opInfos,
21526
- actor: actorID,
21527
- clientSeq: change.getID().getClientSeq(),
21528
- serverSeq: change.getID().getServerSeq()
21529
- },
21530
- rawChange: this.isEnableDevtools() ? change.toStruct() : void 0
21531
- });
21373
+ ]);
21374
+ }
21375
+ /**
21376
+ * `getVersionVector` returns the version vector of document
21377
+ */
21378
+ getVersionVector() {
21379
+ return this.changeID.getVersionVector();
21380
+ }
21381
+ isSameElementOrChildOf(elem, parent) {
21382
+ if (parent === elem) {
21383
+ return true;
21532
21384
  }
21533
- if (change.hasPresenceChange()) {
21534
- event.push({
21535
- type: "presence-changed",
21536
- source: OpSource.UndoRedo,
21537
- value: {
21538
- clientID: actorID,
21539
- presence: this.getPresence(actorID)
21540
- }
21541
- });
21385
+ const nodePath = elem.split(".");
21386
+ return parent.split(".").every((path, index) => path === nodePath[index]);
21387
+ }
21388
+ /**
21389
+ * `removePushedLocalChanges` removes local changes that have been applied to
21390
+ * the server from the local changes.
21391
+ *
21392
+ * @param clientSeq - client sequence number to remove local changes before it
21393
+ */
21394
+ removePushedLocalChanges(clientSeq) {
21395
+ while (this.localChanges.length) {
21396
+ const change = this.localChanges[0];
21397
+ if (change.getID().getClientSeq() > clientSeq) {
21398
+ break;
21399
+ }
21400
+ this.localChanges.shift();
21542
21401
  }
21543
- this.publish(event);
21544
21402
  }
21545
21403
  /**
21546
- * `redo` redoes the last operation executed by the current client.
21547
- * It does not impact operations made by other clients.
21404
+ * `executeUndoRedo` executes undo or redo operation with shared logic.
21548
21405
  */
21549
- redo() {
21406
+ executeUndoRedo(isUndo) {
21550
21407
  if (this.isUpdating) {
21551
21408
  throw new YorkieError(
21552
21409
  Code.ErrRefused,
21553
- "Redo is not allowed during an update"
21410
+ `${isUndo ? "Undo" : "Redo"} is not allowed during an update`
21554
21411
  );
21555
21412
  }
21556
- const redoOps = this.internalHistory.popRedo();
21557
- if (redoOps === void 0) {
21413
+ const ops = isUndo ? this.internalHistory.popUndo() : this.internalHistory.popRedo();
21414
+ if (!ops) {
21558
21415
  throw new YorkieError(
21559
21416
  Code.ErrRefused,
21560
- "There is no operation to be redone"
21417
+ `There is no operation to be ${isUndo ? "undone" : "redone"}`
21561
21418
  );
21562
21419
  }
21563
21420
  this.ensureClone();
21564
- const context = ChangeContext.create(
21421
+ const ctx = ChangeContext.create(
21565
21422
  this.changeID,
21566
21423
  this.clone.root,
21567
21424
  this.clone.presences.get(this.changeID.getActorID()) || {}
21568
21425
  );
21569
- for (const redoOp of redoOps) {
21570
- if (!(redoOp instanceof Operation)) {
21426
+ for (const op of ops) {
21427
+ if (!(op instanceof Operation)) {
21571
21428
  const presence = new Presence(
21572
- context,
21429
+ ctx,
21573
21430
  deepcopy(this.clone.presences.get(this.changeID.getActorID()))
21574
21431
  );
21575
- presence.set(redoOp.value, { addToHistory: true });
21432
+ presence.set(op.value, { addToHistory: true });
21576
21433
  continue;
21577
21434
  }
21578
- const ticket = context.issueTimeTicket();
21579
- redoOp.setExecutedAt(ticket);
21580
- if (redoOp instanceof ArraySetOperation) {
21581
- const prev = redoOp.getCreatedAt();
21582
- redoOp.getValue().setCreatedAt(ticket);
21435
+ const ticket = ctx.issueTimeTicket();
21436
+ op.setExecutedAt(ticket);
21437
+ if (op instanceof ArraySetOperation) {
21438
+ const prev = op.getCreatedAt();
21439
+ op.getValue().setCreatedAt(ticket);
21583
21440
  this.internalHistory.reconcileCreatedAt(prev, ticket);
21584
- } else if (redoOp instanceof AddOperation) {
21585
- const prev = redoOp.getValue().getCreatedAt();
21586
- redoOp.getValue().setCreatedAt(ticket);
21441
+ } else if (op instanceof AddOperation) {
21442
+ const prev = op.getValue().getCreatedAt();
21443
+ op.getValue().setCreatedAt(ticket);
21587
21444
  this.internalHistory.reconcileCreatedAt(prev, ticket);
21588
21445
  }
21589
- context.push(redoOp);
21446
+ ctx.push(op);
21590
21447
  }
21591
- const change = context.toChange();
21448
+ const change = ctx.toChange();
21592
21449
  change.execute(this.clone.root, this.clone.presences, OpSource.UndoRedo);
21593
21450
  const { opInfos, reverseOps } = change.execute(
21594
21451
  this.root,
21595
21452
  this.presences,
21596
21453
  OpSource.UndoRedo
21597
21454
  );
21598
- const reversePresence = context.getReversePresence();
21599
- if (reversePresence) {
21600
- reverseOps.push({
21601
- type: "presence",
21602
- value: reversePresence
21603
- });
21455
+ const reverse = ctx.getReversePresence();
21456
+ if (reverse) {
21457
+ reverseOps.push({ type: "presence", value: reverse });
21604
21458
  }
21605
- if (reverseOps.length > 0) {
21606
- this.internalHistory.pushUndo(reverseOps);
21459
+ if (reverseOps.length) {
21460
+ if (isUndo) {
21461
+ this.internalHistory.pushRedo(reverseOps);
21462
+ } else {
21463
+ this.internalHistory.pushUndo(reverseOps);
21464
+ }
21607
21465
  }
21608
- if (!change.hasPresenceChange() && opInfos.length === 0) {
21466
+ if (!change.hasPresenceChange() && !opInfos.length) {
21609
21467
  return;
21610
21468
  }
21611
21469
  this.localChanges.push(change);
21612
- this.changeID = context.getNextID();
21470
+ this.changeID = ctx.getNextID();
21613
21471
  const actorID = this.changeID.getActorID();
21614
- const event = [];
21615
- if (opInfos.length > 0) {
21616
- event.push({
21472
+ const events = [];
21473
+ if (opInfos.length) {
21474
+ events.push({
21617
21475
  type: "local-change",
21618
21476
  source: OpSource.UndoRedo,
21619
21477
  value: {
@@ -21627,7 +21485,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21627
21485
  });
21628
21486
  }
21629
21487
  if (change.hasPresenceChange()) {
21630
- event.push({
21488
+ events.push({
21631
21489
  type: "presence-changed",
21632
21490
  source: OpSource.UndoRedo,
21633
21491
  value: {
@@ -21636,36 +21494,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21636
21494
  }
21637
21495
  });
21638
21496
  }
21639
- this.publish(event);
21640
- }
21641
- /**
21642
- * `getUndoStackForTest` returns the undo stack for test.
21643
- */
21644
- getUndoStackForTest() {
21645
- return this.internalHistory.getUndoStackForTest();
21646
- }
21647
- /**
21648
- * `getRedoStackForTest` returns the redo stack for test.
21649
- */
21650
- getRedoStackForTest() {
21651
- return this.internalHistory.getRedoStackForTest();
21652
- }
21653
- /**
21654
- * `broadcast` the payload to the given topic.
21655
- */
21656
- broadcast(topic, payload, options) {
21657
- const broadcastEvent = {
21658
- type: "local-broadcast",
21659
- value: { topic, payload },
21660
- options
21661
- };
21662
- this.publish([broadcastEvent]);
21663
- }
21664
- /**
21665
- * `getVersionVector` returns the version vector of document
21666
- */
21667
- getVersionVector() {
21668
- return this.changeID.getVersionVector();
21497
+ this.publish(events);
21669
21498
  }
21670
21499
  }
21671
21500
  function createAuthInterceptor(apiKey, token) {
@@ -21688,7 +21517,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21688
21517
  };
21689
21518
  }
21690
21519
  const name$1 = "@yorkie-js/sdk";
21691
- const version$1 = "0.6.27";
21520
+ const version$1 = "0.6.29";
21692
21521
  const pkg$1 = {
21693
21522
  name: name$1,
21694
21523
  version: version$1
@@ -21786,11 +21615,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21786
21615
  createMetricInterceptor(opts == null ? void 0 : opts.userAgent)
21787
21616
  ],
21788
21617
  fetch: (input, init) => {
21789
- const newInit = {
21618
+ return fetch(input, {
21790
21619
  ...init,
21791
21620
  keepalive: this.keepalive
21792
- };
21793
- return fetch(input, newInit);
21621
+ });
21794
21622
  }
21795
21623
  })
21796
21624
  );
@@ -21841,15 +21669,20 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
21841
21669
  * immediately using `fetch` with the `keepalive` option enabled. This is
21842
21670
  * useful for ensuring the deactivation request completes even if the page is
21843
21671
  * being unloaded, such as in `beforeunload` or `unload` event listeners.
21672
+ * If synchronous is true, the server will wait for all pending operations to
21673
+ * complete before deactivating.
21844
21674
  */
21845
- deactivate(options = { keepalive: false }) {
21675
+ deactivate(options = { keepalive: false, synchronous: false }) {
21846
21676
  if (this.status === "deactivated") {
21847
21677
  return Promise.resolve();
21848
21678
  }
21849
21679
  const task = async () => {
21850
21680
  try {
21851
21681
  await this.rpcClient.deactivateClient(
21852
- { clientId: this.id },
21682
+ {
21683
+ clientId: this.id,
21684
+ synchronous: options.synchronous
21685
+ },
21853
21686
  { headers: { "x-shard-key": `${this.apiKey}/${this.key}` } }
21854
21687
  );
21855
21688
  this.deactivateInternal();
@@ -22579,7 +22412,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
22579
22412
  };
22580
22413
  }
22581
22414
  const name = "@yorkie-js/react";
22582
- const version = "0.6.27";
22415
+ const version = "0.6.29";
22583
22416
  const pkg = {
22584
22417
  name,
22585
22418
  version