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