@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.
- package/dist/yorkie-js-react.es.js +665 -832
- package/dist/yorkie-js-react.es.js.map +1 -1
- package/dist/yorkie-js-react.js +665 -832
- package/dist/yorkie-js-react.js.map +1 -1
- package/package.json +2 -2
|
@@ -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
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
|
|
18066
|
-
|
|
18067
|
-
|
|
18068
|
-
|
|
18069
|
-
|
|
18070
|
-
|
|
18071
|
-
|
|
18072
|
-
|
|
18073
|
-
|
|
18074
|
-
|
|
18075
|
-
|
|
18076
|
-
|
|
18077
|
-
|
|
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
|
|
20133
|
-
constructor(
|
|
20134
|
-
|
|
20135
|
-
|
|
20136
|
-
|
|
20137
|
-
this
|
|
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
|
-
* `
|
|
19750
|
+
* `create` creates a new instance of Root.
|
|
20141
19751
|
*/
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
20445
|
-
canRedo: this.
|
|
20446
|
-
undo: this.
|
|
20447
|
-
redo: 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
|
|
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
|
-
|
|
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
|
|
20487
|
-
if (!
|
|
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 (!
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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
|
|
20504
|
+
if (reverseOps.length) {
|
|
20535
20505
|
this.internalHistory.pushUndo(reverseOps);
|
|
20536
20506
|
}
|
|
20537
|
-
if (opInfos.length
|
|
20507
|
+
if (opInfos.length) {
|
|
20538
20508
|
this.internalHistory.clearRedo();
|
|
20539
20509
|
}
|
|
20540
|
-
this.changeID =
|
|
20510
|
+
this.changeID = ctx.getNextID();
|
|
20541
20511
|
const event = [];
|
|
20542
|
-
if (opInfos.length
|
|
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(
|
|
20734
|
+
publish(events) {
|
|
20765
20735
|
if (this.eventStreamObserver) {
|
|
20766
|
-
this.eventStreamObserver.next(
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
21054
|
+
if (opInfos.length) {
|
|
21130
21055
|
const rawChange = this.isEnableDevtools() ? change.toStruct() : void 0;
|
|
21131
|
-
|
|
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 (
|
|
21158
|
-
this.publish(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
21227
|
-
this.publish(
|
|
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
|
-
* `
|
|
21173
|
+
* `applyDocEventsForReplay` applies the given events into this document.
|
|
21249
21174
|
*/
|
|
21250
|
-
|
|
21251
|
-
|
|
21252
|
-
|
|
21253
|
-
|
|
21254
|
-
|
|
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
|
-
|
|
21257
|
-
|
|
21258
|
-
|
|
21259
|
-
|
|
21260
|
-
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
21269
|
-
|
|
21270
|
-
|
|
21271
|
-
|
|
21272
|
-
|
|
21273
|
-
|
|
21274
|
-
|
|
21275
|
-
|
|
21276
|
-
|
|
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
|
|
21317
|
-
|
|
21230
|
+
const paths = path.split(".");
|
|
21231
|
+
paths.shift();
|
|
21318
21232
|
let value = this.getRoot();
|
|
21319
|
-
for (const key of
|
|
21233
|
+
for (const key of paths) {
|
|
21320
21234
|
value = value[key];
|
|
21321
|
-
if (value
|
|
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
|
-
* `
|
|
21350
|
+
* `getUndoStackForTest` returns the undo stack for test.
|
|
21437
21351
|
*/
|
|
21438
|
-
|
|
21439
|
-
return this.internalHistory.
|
|
21352
|
+
getUndoStackForTest() {
|
|
21353
|
+
return this.internalHistory.getUndoStackForTest();
|
|
21440
21354
|
}
|
|
21441
21355
|
/**
|
|
21442
|
-
* `
|
|
21356
|
+
* `getRedoStackForTest` returns the redo stack for test.
|
|
21443
21357
|
*/
|
|
21444
|
-
|
|
21445
|
-
return this.internalHistory.
|
|
21358
|
+
getRedoStackForTest() {
|
|
21359
|
+
return this.internalHistory.getRedoStackForTest();
|
|
21446
21360
|
}
|
|
21447
21361
|
/**
|
|
21448
|
-
* `
|
|
21449
|
-
* It does not impact operations made by other clients.
|
|
21362
|
+
* `broadcast` the payload to the given topic.
|
|
21450
21363
|
*/
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
|
|
21455
|
-
|
|
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
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
21501
|
-
|
|
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
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
21535
|
-
|
|
21536
|
-
|
|
21537
|
-
|
|
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
|
-
* `
|
|
21545
|
-
* It does not impact operations made by other clients.
|
|
21402
|
+
* `executeUndoRedo` executes undo or redo operation with shared logic.
|
|
21546
21403
|
*/
|
|
21547
|
-
|
|
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
|
|
21555
|
-
if (
|
|
21411
|
+
const ops = isUndo ? this.internalHistory.popUndo() : this.internalHistory.popRedo();
|
|
21412
|
+
if (!ops) {
|
|
21556
21413
|
throw new YorkieError(
|
|
21557
21414
|
Code.ErrRefused,
|
|
21558
|
-
|
|
21415
|
+
`There is no operation to be ${isUndo ? "undone" : "redone"}`
|
|
21559
21416
|
);
|
|
21560
21417
|
}
|
|
21561
21418
|
this.ensureClone();
|
|
21562
|
-
const
|
|
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
|
|
21568
|
-
if (!(
|
|
21424
|
+
for (const op of ops) {
|
|
21425
|
+
if (!(op instanceof Operation)) {
|
|
21569
21426
|
const presence = new Presence(
|
|
21570
|
-
|
|
21427
|
+
ctx,
|
|
21571
21428
|
deepcopy(this.clone.presences.get(this.changeID.getActorID()))
|
|
21572
21429
|
);
|
|
21573
|
-
presence.set(
|
|
21430
|
+
presence.set(op.value, { addToHistory: true });
|
|
21574
21431
|
continue;
|
|
21575
21432
|
}
|
|
21576
|
-
const ticket =
|
|
21577
|
-
|
|
21578
|
-
if (
|
|
21579
|
-
const prev =
|
|
21580
|
-
|
|
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 (
|
|
21583
|
-
const prev =
|
|
21584
|
-
|
|
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
|
-
|
|
21444
|
+
ctx.push(op);
|
|
21588
21445
|
}
|
|
21589
|
-
const change =
|
|
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
|
|
21597
|
-
if (
|
|
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
|
|
21604
|
-
|
|
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
|
|
21464
|
+
if (!change.hasPresenceChange() && !opInfos.length) {
|
|
21607
21465
|
return;
|
|
21608
21466
|
}
|
|
21609
21467
|
this.localChanges.push(change);
|
|
21610
|
-
this.changeID =
|
|
21468
|
+
this.changeID = ctx.getNextID();
|
|
21611
21469
|
const actorID = this.changeID.getActorID();
|
|
21612
|
-
const
|
|
21613
|
-
if (opInfos.length
|
|
21614
|
-
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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
|
-
{
|
|
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.
|
|
22413
|
+
const version = "0.6.29";
|
|
22581
22414
|
const pkg = {
|
|
22582
22415
|
name,
|
|
22583
22416
|
version
|