From 859c019ddfe0a35f3dc84dba5b92dd3c10491eb5 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:12:22 +0900 Subject: [PATCH 01/48] Support Undo/Redo for object.set and object.remove operations (#658) 1. Define reverse operations of Object.Set Object.Remove: 1.1 Modified the set operation to compare `executedAt` with `getPositionedAt()` during value setting, addressing issues during undo. 1.2 Set `movedAt` when the value is reassigned during undo. 2. Handle edge cases: When the target element is deleted by other peers Implemented handling to skip execution of reverse operations during undo and redo if the element has been deleted. 3. Add whiteboard example: 3.1. Feature Introduction - Added a whiteboard example for testing undo redo operations. 3.2. Variables Added for Displaying Yorkie Data - Added `CRDTRoot.opsForTest` and `CRDTElement.toJSForTest`. 3.3. Additional Features to Apply (Todo) - Planned features include implementing history pause/resume, subscribing to history changes, and applying reverse operations for `array.add` and `array.remove`. 4. TODOs 4.1. Set nested objects (yorkie-team/yorkie#663) - Modified set operation to handle nested objects. 4.2. When the target element is garbage-collected (yorkie-team/yorkie#664) - Considering elements referenced by operations in the undo/redo stack during garbage collection. --------- Co-authored-by: Youngteac Hong --- public/devtool/object.css | 147 ++++++ public/devtool/object.js | 121 +++++ public/whiteboard.css | 119 +++++ public/whiteboard.html | 384 +++++++++++++++ src/api/converter.ts | 4 +- src/document/change/change.ts | 15 +- src/document/change/context.ts | 2 +- src/document/crdt/array.ts | 46 +- src/document/crdt/counter.ts | 12 + src/document/crdt/element.ts | 29 +- src/document/crdt/element_rht.ts | 33 +- src/document/crdt/object.ts | 49 +- src/document/crdt/primitive.ts | 12 + src/document/crdt/rga_tree_list.ts | 21 +- src/document/crdt/root.ts | 7 + src/document/crdt/text.ts | 12 + src/document/crdt/tree.ts | 12 + src/document/document.ts | 111 +++-- src/document/history.ts | 16 +- src/document/json/array.ts | 37 +- src/document/json/object.ts | 12 +- src/document/operation/increase_operation.ts | 6 +- src/document/operation/operation.ts | 26 +- src/document/operation/remove_operation.ts | 58 ++- src/document/operation/set_operation.ts | 47 +- src/types/devtools_element.ts | 38 ++ test/helper/helper.ts | 12 +- test/integration/counter_test.ts | 18 +- test/integration/document_test.ts | 10 +- test/integration/object_test.ts | 476 ++++++++++++++++++- test/integration/presence_test.ts | 20 +- test/unit/document/crdt/root_test.ts | 25 +- test/unit/document/document_test.ts | 11 + 33 files changed, 1758 insertions(+), 190 deletions(-) create mode 100644 public/devtool/object.css create mode 100644 public/devtool/object.js create mode 100644 public/whiteboard.css create mode 100644 public/whiteboard.html create mode 100644 src/types/devtools_element.ts diff --git a/public/devtool/object.css b/public/devtool/object.css new file mode 100644 index 000000000..b0ed7be3a --- /dev/null +++ b/public/devtool/object.css @@ -0,0 +1,147 @@ +.devtool-root-holder, +.devtool-ops-holder { + display: flex; + flex-direction: column; + height: 100%; + overflow-y: scroll; + font-size: 14px; + font-weight: 400; +} + +.devtool-root-holder .object-content { + margin-left: 24px; +} + +.devtool-root-holder .object-key-val, +.devtool-root-holder .object-val { + position: relative; +} + +.devtool-root-holder .object-key-val:not(:last-of-type):before, +.devtool-root-holder .object-val:not(:last-of-type):before { + border: 1px dashed #ddd; + border-width: 0 0 0 1px; + content: ''; + position: absolute; + bottom: -12px; + left: -18px; + top: 12px; +} + +.devtool-root-holder .object-key-val:after, +.devtool-root-holder .object-val:after { + border-bottom: 1px dashed #ddd; + border-left: 1px dashed #ddd; + border-radius: 0 0 0 4px; + border-right: 0 dashed #ddd; + border-top: 0 dashed #ddd; + content: ''; + height: 16px; + position: absolute; + top: 0; + width: 16px; + height: 32px; + top: -16px; + left: -18px; +} + +.devtool-root-holder > .object-key-val:after, +.devtool-root-holder > .object-val:after { + content: none; +} + +.devtool-root-holder .object-val > span, +.devtool-root-holder .object-key-val > span, +.devtool-root-holder .object-val label, +.devtool-root-holder .object-key-val label { + border: 1px solid #ddd; + border-radius: 4px; + display: inline-block; + font-size: 14px; + font-weight: 500; + letter-spacing: 0 !important; + line-height: 1.72; + margin-bottom: 16px; + padding: 6px 8px; +} + +.devtool-root-holder label { + cursor: pointer; +} + +.devtool-root-holder .object-key-val label:before { + content: '▾'; + margin-right: 4px; +} + +.devtool-root-holder input[type='checkbox']:checked + label:before { + content: '▸'; +} + +.devtool-root-holder input[type='checkbox']:checked ~ .object-content { + display: none; +} + +.devtool-root-holder input[type='checkbox'] { + display: none; +} + +.devtool-root-holder .timeticket, +.devtool-ops-holder .timeticket { + border-radius: 4px; + background: #f1f2f3; + font-size: 12px; + font-weight: 400; + padding: 2px 6px; + margin-left: 4px; + letter-spacing: 1px; +} + +.devtool-ops-holder .change { + display: flex; + margin-bottom: 3px; + border-top: 1px solid #ddd; + word-break: break-all; +} +.devtool-ops-holder label { + position: relative; + overflow: hidden; + padding-left: 24px; + cursor: pointer; + line-height: 1.6; +} +.devtool-ops-holder input[type='checkbox']:checked + label { + height: 22px; +} +.devtool-ops-holder input[type='checkbox'] { + display: none; +} +.devtool-ops-holder .count { + position: absolute; + left: 0px; + display: flex; + justify-content: center; + width: 20px; + height: 20px; + font-size: 13px; +} +.devtool-ops-holder .op { + display: block; +} +.devtool-ops-holder .op:first-child { + display: inline-block; +} +.devtool-ops-holder .op .type { + padding: 0 4px; + border-radius: 4px; + background: #e6e6fa; +} +.devtool-ops-holder .op .type.set { + background: #cff7cf; +} +.devtool-ops-holder .op .type.remove { + background: #f9c0c8; +} +.devtool-ops-holder .op .type.add { + background: #add8e6; +} diff --git a/public/devtool/object.js b/public/devtool/object.js new file mode 100644 index 000000000..994786f23 --- /dev/null +++ b/public/devtool/object.js @@ -0,0 +1,121 @@ +const objectDevtool = ( + doc, + { rootHolder, opsHolder, undoOpsHolder, redoOpsHolder }, +) => { + const displayRootObject = () => { + const rootObj = doc.getRoot().toJSForTest(); + rootHolder.innerHTML = ` +
+ ${renderContainer(rootObj)} +
+ `; + }; + + const renderContainer = ({ key, value, id }) => { + const valueHTML = Object.values(value) + .map((v) => { + return v.type === 'YORKIE_OBJECT' || v.type === 'YORKIE_ARRAY' + ? renderContainer(v) + : renderValue(v); + }) + .join(''); + if (key === undefined) key = 'root'; + return ` +
+ ${renderKey({ key, id })} +
+ ${valueHTML} +
+
+ `; + }; + + const renderKey = ({ key, id }) => { + return ` + + + `; + }; + + const renderValue = ({ key, value, id }) => { + return ` +
+ ${key} : ${JSON.stringify(value)} + ${id} + +
+ `; + }; + + const displayOps = () => { + opsHolder.innerHTML = ` +
+ ${renderOpsHolder(doc.getOpsForTest(), 'op')} +
+ `; + }; + + const displayUndoOps = () => { + undoOpsHolder.innerHTML = ` +
+ ${renderOpsHolder(doc.getUndoStackForTest(), 'undo')} +
+ `; + }; + + const displayRedoOps = () => { + redoOpsHolder.innerHTML = ` +
+ ${renderOpsHolder(doc.getRedoStackForTest(), 'redo')} +
+ `; + }; + + const renderOpsHolder = (changes, idPrefix) => { + return changes + .map((ops, i) => { + const opsStr = ops + .map((op) => { + if (op.type === 'presence') { + return `presence${JSON.stringify( + op.value, + )}`; + } + const opType = op.toTestString().split('.')[1]; + try { + const id = op.getExecutedAt()?.toTestString(); + return ` + + ${opType} + ${`${id}`}${op.toTestString()} + `; + } catch (e) { + // operation in the undo/redo stack does not yet have "executedAt" set. + return ` + + ${opType} + ${op.toTestString()} + `; + } + }) + .join('\n'); + return ` +
+ + +
+ `; + }) + .reverse() + .join(''); + }; + + return { displayRootObject, displayOps, displayUndoOps, displayRedoOps }; +}; + +export default objectDevtool; diff --git a/public/whiteboard.css b/public/whiteboard.css new file mode 100644 index 000000000..e844c878a --- /dev/null +++ b/public/whiteboard.css @@ -0,0 +1,119 @@ +.whiteboard-example { + display: flex; + flex-direction: column; + height: 100vh; +} + +.dev-log-wrap { + display: flex; + flex-direction: column; + height: calc(100vh - 350px); +} +.dev-log { + display: flex; + flex: 1; + overflow: hidden; +} +.dev-log .log-holders { + padding: 10px; +} +.dev-log .log-holders, +.dev-log .log-holder-wrap, +.dev-log .log-holder { + display: flex; + flex-direction: column; + flex: 1; + overflow: hidden; +} +.log-holder-wrap h2 { + margin: 10px 0; +} +.log-holder-wrap .stack-count { + font-weight: normal; + font-size: 14px; +} +.dev-log-wrap .network { + margin-top: 10px; +} + +.canvas { + position: relative; + width: 100%; + height: 350px; +} +.canvas .toolbar { + position: absolute; + bottom: 4px; + left: 50%; + transform: translateX(-50%); + z-index: 2; +} +.toolbar button { + margin: 2px; + padding: 4px 6px; + color: #666; +} +.canvas .shapes { + position: absolute; + width: 100%; + height: 100%; + background: #eee; + overflow: hidden; +} +.canvas .shape { + position: absolute; + width: 50px; + height: 50px; + border-style: solid; + border-width: 2px; +} +.selection-tools { + display: none; + position: absolute; + z-index: 1; + top: 4px; + right: 4px; + background: #fff; + padding: 6px; + border-radius: 4px; + justify-content: center; + gap: 4px; +} +.selection-tools .color-picker { + display: flex; + flex-wrap: wrap; + justify-content: center; + width: 120px; +} +.selection-tools .color { + width: 20px; + height: 20px; + border-radius: 50%; + border: none; + margin: 4px; + border: 1px solid #ddd; +} +.selection-tools .color:nth-child(1) { + background: orangered; +} +.selection-tools .color:nth-child(2) { + background: gold; +} +.selection-tools .color:nth-child(3) { + background: limegreen; +} +.selection-tools .color:nth-child(4) { + background: dodgerblue; +} +.selection-tools .color:nth-child(5) { + background: darkviolet; +} +.selection-tools .color:nth-child(6) { + background: darkorange; +} +.selection-tools .color:nth-child(7) { + background: dimgray; +} +.selection-tools .color:nth-child(8) { + background: white; +} diff --git a/public/whiteboard.html b/public/whiteboard.html new file mode 100644 index 000000000..ba70d3b63 --- /dev/null +++ b/public/whiteboard.html @@ -0,0 +1,384 @@ + + + + + Whiteboard Example + + + + + +
+
+
+ + + + +
+
+
+
+ + + + + + + + +
+
+
+
+
+ + +
+
+
+
+
+

yorkie document

+
+
+
+
+
+

operations

+
+
+
+
+
+

+ undo stack + + [ total: ] +

+
+
+
+

+ redo stack + + [ total: ] +

+
+
+
+
+
+
+ + + + + diff --git a/src/api/converter.ts b/src/api/converter.ts index 689c81fd9..7e5b07a92 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -1197,8 +1197,8 @@ function fromChangePack

( function fromObject(pbObject: PbJSONElement.JSONObject): CRDTObject { const rht = new ElementRHT(); for (const pbRHTNode of pbObject.getNodesList()) { - // eslint-disable-next-line - rht.set(pbRHTNode.getKey(), fromElement(pbRHTNode.getElement()!)); + const value = fromElement(pbRHTNode.getElement()!); + rht.set(pbRHTNode.getKey(), value, value.getPositionedAt()); } const obj = new CRDTObject(fromTimeTicket(pbObject.getCreatedAt())!, rht); diff --git a/src/document/change/change.ts b/src/document/change/change.ts index 910604512..505eb3827 100644 --- a/src/document/change/change.ts +++ b/src/document/change/change.ts @@ -16,6 +16,7 @@ import { ActorID } from '@yorkie-js-sdk/src/document/time/actor_id'; import { + OpSource, Operation, OperationInfo, } from '@yorkie-js-sdk/src/document/operation/operation'; @@ -137,15 +138,26 @@ export class Change

{ public execute( root: CRDTRoot, presences: Map, + source: OpSource, ): { opInfos: Array; reverseOps: Array>; } { const changeOpInfos: Array = []; const reverseOps: Array> = []; + if (process.env.NODE_ENV !== 'production' && this.operations.length) { + root.opsForTest.push(this.operations); + } for (const operation of this.operations) { - const { opInfos, reverseOp } = operation.execute(root); + const executionResult = operation.execute(root, source); + // NOTE(hackerwins): If the element was removed while executing undo/redo, + // the operation is not executed and executionResult is undefined. + if (!executionResult) continue; + const { opInfos, reverseOp } = executionResult; changeOpInfos.push(...opInfos); + + // TODO(hackerwins): This condition should be removed after implementing + // all reverse operations. if (reverseOp) { reverseOps.unshift(reverseOp); } @@ -161,6 +173,7 @@ export class Change

{ presences.delete(this.id.getActorID()!); } } + return { opInfos: changeOpInfos, reverseOps }; } diff --git a/src/document/change/context.ts b/src/document/change/context.ts index d9f726202..e3234922e 100644 --- a/src/document/change/context.ts +++ b/src/document/change/context.ts @@ -153,7 +153,7 @@ export class ChangeContext

{ } /** - * `getReversePresence` returns the reverse presence of this context. + * `toReversePresence` returns the reverse presence of this context. */ public getReversePresence() { if (this.reversePresenceKeys.size === 0) return undefined; diff --git a/src/document/crdt/array.ts b/src/document/crdt/array.ts index 8170ba18c..9ad8513c2 100644 --- a/src/document/crdt/array.ts +++ b/src/document/crdt/array.ts @@ -20,6 +20,7 @@ import { CRDTElement, } from '@yorkie-js-sdk/src/document/crdt/element'; import { RGATreeList } from '@yorkie-js-sdk/src/document/crdt/rga_tree_list'; +import * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; /** * `CRDTArray` represents an array data type containing `CRDTElement`s. @@ -75,27 +76,19 @@ export class CRDTArray extends CRDTContainer { } /** - * `get` returns the element of the given createAt. + * `get` returns the element of the given index. */ - public get(createdAt: TimeTicket): CRDTElement | undefined { - const node = this.elements.get(createdAt); - if (!node || node.isRemoved()) { - return; - } - - return node; + public get(index: number): CRDTElement | undefined { + const node = this.elements.getByIndex(index); + return node?.getValue(); } /** - * `getByIndex` returns the element of the given index. + * `getByID` returns the element of the given createAt. */ - public getByIndex(index: number): CRDTElement | undefined { - const node = this.elements.getByIndex(index); - if (!node) { - return; - } - - return node.getValue(); + public getByID(createdAt: TimeTicket): CRDTElement | undefined { + const node = this.elements.getByID(createdAt); + return node?.getValue(); } /** @@ -206,6 +199,27 @@ export class CRDTArray extends CRDTContainer { return JSON.parse(this.toJSON()); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + const values: Devtools.ContainerValue = {}; + for (let i = 0; i < this.length; i++) { + const { id, value, type } = this.get(i)!.toJSForTest(); + values[i] = { + key: String(i), + id, + value, + type, + }; + } + return { + id: this.getCreatedAt().toTestString(), + value: values, + type: 'YORKIE_ARRAY', + }; + } + /** * `toSortedJSON` returns the sorted JSON encoding of this array. */ diff --git a/src/document/crdt/counter.ts b/src/document/crdt/counter.ts index dc94a1858..cb33c0fc7 100644 --- a/src/document/crdt/counter.ts +++ b/src/document/crdt/counter.ts @@ -23,6 +23,7 @@ import { PrimitiveType, } from '@yorkie-js-sdk/src/document/crdt/primitive'; import { removeDecimal } from '@yorkie-js-sdk/src/util/number'; +import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; export enum CounterType { IntegerCnt, @@ -119,6 +120,17 @@ export class CRDTCounter extends CRDTElement { return this.toJSON(); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + return { + id: this.getCreatedAt().toTestString(), + value: this.value, + type: 'YORKIE_COUNTER', + }; + } + /** * `deepcopy` copies itself deeply. */ diff --git a/src/document/crdt/element.ts b/src/document/crdt/element.ts index 2f9607ec6..7cd93f7e8 100644 --- a/src/document/crdt/element.ts +++ b/src/document/crdt/element.ts @@ -15,6 +15,7 @@ */ import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; +import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; /** * `CRDTElement` represents an element that has `TimeTicket`s. @@ -58,6 +59,18 @@ export abstract class CRDTElement { return this.removedAt; } + /** + * `getPositionedAt` returns the time of this element when it was positioned + * in the document by undo/redo or move operation. + */ + public getPositionedAt(): TimeTicket { + if (!this.movedAt) { + return this.createdAt; + } + + return this.movedAt; + } + /** * `setMovedAt` sets the move time of this element. */ @@ -83,7 +96,7 @@ export abstract class CRDTElement { public remove(removedAt?: TimeTicket): boolean { if ( removedAt && - removedAt.after(this.createdAt) && + removedAt.after(this.getPositionedAt()) && (!this.removedAt || removedAt.after(this.removedAt)) ) { this.removedAt = removedAt; @@ -102,6 +115,7 @@ export abstract class CRDTElement { abstract toJSON(): string; abstract toSortedJSON(): string; + abstract toJSForTest(): Devtools.JSONElement; abstract deepcopy(): CRDTElement; } @@ -126,6 +140,19 @@ export abstract class CRDTContainer extends CRDTElement { abstract getDescendants( callback: (elem: CRDTElement, parent: CRDTContainer) => boolean, ): void; + + /** + * `get` returns the element of the given key or index. This method is called + * by users. So it should return undefined if the element is removed. + */ + abstract get(keyOrIndex: string | number): CRDTElement | undefined; + + /** + * `getByID` returns the element of the given creation time. This method is + * called by internal. So it should return the element even if the element is + * removed. + */ + abstract getByID(createdAt: TimeTicket): CRDTElement | undefined; } /** diff --git a/src/document/crdt/element_rht.ts b/src/document/crdt/element_rht.ts index 79cff5395..d9d3bdadd 100644 --- a/src/document/crdt/element_rht.ts +++ b/src/document/crdt/element_rht.ts @@ -89,24 +89,22 @@ export class ElementRHT { /** * `set` sets the value of the given key. */ - public set(key: string, value: CRDTElement): CRDTElement | undefined { + public set( + key: string, + value: CRDTElement, + executedAt: TimeTicket, + ): CRDTElement | undefined { let removed; const node = this.nodeMapByKey.get(key); - if ( - node != null && - !node.isRemoved() && - node.remove(value.getCreatedAt()) - ) { + if (node != null && !node.isRemoved() && node.remove(executedAt)) { removed = node.getValue(); } const newNode = ElementRHTNode.of(key, value); this.nodeMapByCreatedAt.set(value.getCreatedAt().toIDString(), newNode); - if ( - node == null || - value.getCreatedAt().after(node.getValue().getCreatedAt()) - ) { + if (node == null || executedAt.after(node.getValue().getPositionedAt())) { this.nodeMapByKey.set(key, newNode); + value.setMovedAt(executedAt); } return removed; } @@ -187,15 +185,22 @@ export class ElementRHT { } /** - * `get` returns the value of the given key. + * `getByID` returns the node of the given createdAt. + */ + public getByID(createdAt: TimeTicket): ElementRHTNode | undefined { + return this.nodeMapByCreatedAt.get(createdAt.toIDString()); + } + + /** + * `get` returns the node of the given key. */ - public get(key: string): CRDTElement | undefined { + public get(key: string): ElementRHTNode | undefined { const node = this.nodeMapByKey.get(key); - if (node == null) { + if (!node || node.isRemoved()) { return; } - return node.getValue(); + return node; } // eslint-disable-next-line jsdoc/require-jsdoc diff --git a/src/document/crdt/object.ts b/src/document/crdt/object.ts index 81b9ceb63..86b650a61 100644 --- a/src/document/crdt/object.ts +++ b/src/document/crdt/object.ts @@ -20,6 +20,7 @@ import { CRDTElement, } from '@yorkie-js-sdk/src/document/crdt/element'; import { ElementRHT } from '@yorkie-js-sdk/src/document/crdt/element_rht'; +import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; /** * `CRDTObject` represents an object data type, but unlike regular JSON, @@ -59,8 +60,12 @@ export class CRDTObject extends CRDTContainer { /** * `set` sets the given element of the given key. */ - public set(key: string, value: CRDTElement): CRDTElement | undefined { - return this.memberNodes.set(key, value); + public set( + key: string, + value: CRDTElement, + executedAt: TimeTicket, + ): CRDTElement | undefined { + return this.memberNodes.set(key, value, executedAt); } /** @@ -84,7 +89,16 @@ export class CRDTObject extends CRDTContainer { * `get` returns the value of the given key. */ public get(key: string): CRDTElement | undefined { - return this.memberNodes.get(key); + const node = this.memberNodes.get(key); + return node?.getValue(); + } + + /** + * `getByID` returns the element of the given createAt. + */ + public getByID(createdAt: TimeTicket): CRDTElement | undefined { + const node = this.memberNodes.getByID(createdAt); + return node?.getValue(); } /** @@ -112,6 +126,27 @@ export class CRDTObject extends CRDTContainer { return JSON.parse(this.toJSON()); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + const values: Devtools.ContainerValue = {}; + for (const [key, elem] of this) { + const { id, value, type } = elem.toJSForTest(); + values[key] = { + key, + id, + value, + type, + }; + } + return { + id: this.getCreatedAt().toTestString(), + value: values, + type: 'YORKIE_OBJECT', + }; + } + /** * `getKeys` returns array of keys in this object. */ @@ -135,7 +170,7 @@ export class CRDTObject extends CRDTContainer { const json = []; for (const key of keys.sort()) { - const node = this.memberNodes.get(key); + const node = this.memberNodes.get(key)?.getValue(); json.push(`"${key}":${node!.toSortedJSON()}`); } @@ -155,7 +190,11 @@ export class CRDTObject extends CRDTContainer { public deepcopy(): CRDTObject { const clone = CRDTObject.create(this.getCreatedAt()); for (const node of this.memberNodes) { - clone.memberNodes.set(node.getStrKey(), node.getValue().deepcopy()); + clone.memberNodes.set( + node.getStrKey(), + node.getValue().deepcopy(), + this.getPositionedAt(), + ); } clone.remove(this.getRemovedAt()); return clone; diff --git a/src/document/crdt/primitive.ts b/src/document/crdt/primitive.ts index fbaf9ccda..b3c4b440c 100644 --- a/src/document/crdt/primitive.ts +++ b/src/document/crdt/primitive.ts @@ -19,6 +19,7 @@ import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { escapeString } from '@yorkie-js-sdk/src/document/json/strings'; +import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; export enum PrimitiveType { Null, @@ -117,6 +118,17 @@ export class Primitive extends CRDTElement { return this.toJSON(); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + return { + id: this.getCreatedAt().toTestString(), + value: this.value, + type: 'YORKIE_PRIMITIVE', + }; + } + /** * `deepcopy` copies itself deeply. */ diff --git a/src/document/crdt/rga_tree_list.ts b/src/document/crdt/rga_tree_list.ts index 3a1add11b..df7bd0854 100644 --- a/src/document/crdt/rga_tree_list.ts +++ b/src/document/crdt/rga_tree_list.ts @@ -69,15 +69,11 @@ class RGATreeListNode extends SplayNode { } /** - * `getPositionedAt` returns time this element was positioned in the array. + * `getPositionedAt` returns the time of this element when it was positioned + * in the array. */ public getPositionedAt(): TimeTicket { - const movedAt = this.value.getMovedAt(); - if (movedAt) { - return movedAt; - } - - return this.value.getCreatedAt(); + return this.value.getPositionedAt(); } /** @@ -263,15 +259,10 @@ export class RGATreeList { } /** - * `get` returns the element of the given creation time. + * `getByID` returns the element of the given creation time. */ - public get(createdAt: TimeTicket): CRDTElement | undefined { - const node = this.nodeMapByCreatedAt.get(createdAt.toIDString()); - if (!node) { - return; - } - - return node.getValue(); + public getByID(createdAt: TimeTicket): RGATreeListNode | undefined { + return this.nodeMapByCreatedAt.get(createdAt.toIDString()); } /** diff --git a/src/document/crdt/root.ts b/src/document/crdt/root.ts index ad100a8bf..5e0c89596 100644 --- a/src/document/crdt/root.ts +++ b/src/document/crdt/root.ts @@ -25,6 +25,7 @@ import { CRDTGCElement, } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; +import { Operation } from '@yorkie-js-sdk/src/document/operation/operation'; /** * `CRDTElementPair` is a structure that represents a pair of element and its @@ -69,12 +70,18 @@ export class CRDTRoot { * the element that has removed nodes when executing garbage collection. */ private elementHasRemovedNodesSetByCreatedAt: Set; + /** + * `opsForTest` is used for debugging the entire operation. + * operations accumulate only in dev mode. + */ + public opsForTest: Array>; constructor(rootObject: CRDTObject) { this.rootObject = rootObject; this.elementPairMapByCreatedAt = new Map(); this.removedElementSetByCreatedAt = new Set(); this.elementHasRemovedNodesSetByCreatedAt = new Set(); + this.opsForTest = []; this.elementPairMapByCreatedAt.set( this.rootObject.getCreatedAt().toIDString(), diff --git a/src/document/crdt/text.ts b/src/document/crdt/text.ts index b998aef1b..ee42dd8f3 100644 --- a/src/document/crdt/text.ts +++ b/src/document/crdt/text.ts @@ -30,6 +30,7 @@ import { } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split'; import { escapeString } from '@yorkie-js-sdk/src/document/json/strings'; import { parseObjectValues } from '@yorkie-js-sdk/src/util/object'; +import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; /** * `TextChangeType` is the type of TextChange. @@ -350,6 +351,17 @@ export class CRDTText extends CRDTGCElement { return this.toJSON(); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + return { + id: this.getCreatedAt().toTestString(), + value: JSON.parse(this.toJSON()), + type: 'YORKIE_TEXT', + }; + } + /** * `toString` returns the string representation of this text. */ diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index d456908ab..152799df1 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -38,6 +38,7 @@ import type { TreeNodeType, } from '@yorkie-js-sdk/src/util/index_tree'; import { Indexable } from '@yorkie-js-sdk/src/document/document'; +import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; export type TreeNode = TextNode | ElementNode; @@ -990,6 +991,17 @@ export class CRDTTree extends CRDTGCElement { return JSON.stringify(this.getRootTreeNode()); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + return { + id: this.getCreatedAt().toTestString(), + value: JSON.parse(this.toJSON()), + type: 'YORKIE_TREE', + }; + } + /** * `getRootTreeNode` returns the converted value of this tree to TreeNode. */ diff --git a/src/document/document.ts b/src/document/document.ts index d5b5f8f29..097acc8ca 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -50,6 +50,7 @@ import { } from '@yorkie-js-sdk/src/document/change/checkpoint'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { + OpSource, OperationInfo, ObjectOperationInfo, TextOperationInfo, @@ -66,7 +67,7 @@ import { Presence, PresenceChangeType, } from '@yorkie-js-sdk/src/document/presence/presence'; -import { History } from '@yorkie-js-sdk/src/document/history'; +import { History, HistoryOperation } from '@yorkie-js-sdk/src/document/history'; /** * `DocumentOptions` are the options to create a new document. @@ -525,7 +526,11 @@ export class Document { } const change = context.getChange(); - const { opInfos, reverseOps } = change.execute(this.root, this.presences); + const { opInfos, reverseOps } = change.execute( + this.root, + this.presences, + OpSource.Local, + ); const reversePresence = context.getReversePresence(); if (reversePresence) { reverseOps.push({ @@ -538,10 +543,14 @@ export class Document { if (reverseOps.length > 0) { this.internalHistory.pushUndo(reverseOps); } - this.internalHistory.clearRedo(); + // NOTE(chacha912): Clear redo when a new local operation is applied. + if (opInfos.length > 0) { + this.internalHistory.clearRedo(); + } this.changeID = change.getID(); - if (change.hasOperations()) { + // 03. Publish the document change event. + if (opInfos.length > 0) { this.publish({ type: DocEventType.LocalChange, value: { @@ -943,6 +952,13 @@ export class Document { return createJSON(context, this.clone!.root.getObject()); } + /** + * `getOpsForTest` returns the operations of this document for testing. + */ + public getOpsForTest() { + return this.root.opsForTest; + } + /** * `garbageCollect` purges elements that were removed before the given time. * @@ -1040,9 +1056,8 @@ export class Document { this.ensureClone(); for (const change of changes) { - change.execute(this.clone!.root, this.clone!.presences); + change.execute(this.clone!.root, this.clone!.presences, OpSource.Remote); - let changeInfo: ChangeInfo | undefined; let presenceEvent: | WatchedEvent

| UnwatchedEvent

@@ -1086,23 +1101,24 @@ export class Document { } } - const executionResult = change.execute(this.root, this.presences); - if (change.hasOperations()) { - changeInfo = { - actor: actorID, - message: change.getMessage() || '', - operations: executionResult.opInfos, - }; - } + const { opInfos } = change.execute( + this.root, + this.presences, + OpSource.Remote, + ); // DocEvent should be emitted synchronously with applying changes. // This is because 3rd party model should be synced with the Document // after RemoteChange event is emitted. If the event is emitted // asynchronously, the model can be changed and breaking consistency. - if (changeInfo) { + if (opInfos.length > 0) { this.publish({ type: DocEventType.RemoteChange, - value: changeInfo, + value: { + actor: actorID, + message: change.getMessage() || '', + operations: opInfos, + }, }); } if (presenceEvent) { @@ -1261,6 +1277,7 @@ export class Document { // apply undo operation in the context to generate a change for (const undoOp of undoOps) { if (!(undoOp instanceof Operation)) { + // apply presence change to the context const presence = new Presence

( context, deepcopy(this.clone!.presences.get(this.changeID.getActorID()!)!), @@ -1274,16 +1291,13 @@ export class Document { } const change = context.getChange(); - try { - change.execute(this.clone!.root, this.clone!.presences); - } catch (err) { - // drop clone because it is contaminated. - this.clone = undefined; - logger.error(err); - throw err; - } + change.execute(this.clone!.root, this.clone!.presences, OpSource.UndoRedo); - const { opInfos, reverseOps } = change.execute(this.root, this.presences); + const { opInfos, reverseOps } = change.execute( + this.root, + this.presences, + OpSource.UndoRedo, + ); const reversePresence = context.getReversePresence(); if (reversePresence) { reverseOps.push({ @@ -1295,11 +1309,19 @@ export class Document { this.internalHistory.pushRedo(reverseOps); } - this.localChanges.push(change); - this.changeID = change.getID(); + // TODO(chacha912): When there is no applied operation or presence + // during undo/redo, skip propagating change remotely. + // In the database, it may appear as if the client sequence is missing. + if (change.hasPresenceChange() || opInfos.length > 0) { + this.localChanges.push(change); + } + this.changeID = change.getID(); const actorID = this.changeID.getActorID()!; - if (change.hasOperations()) { + // NOTE(chacha912): Although operations are included in the change, they + // may not be executable (e.g., when the target element has been deleted). + // So we check opInfos, which represent the actually executed operations. + if (opInfos.length > 0) { this.publish({ type: DocEventType.LocalChange, value: { @@ -1344,6 +1366,7 @@ export class Document { // apply redo operation in the context to generate a change for (const redoOp of redoOps) { if (!(redoOp instanceof Operation)) { + // apply presence change to the context const presence = new Presence

( context, deepcopy(this.clone!.presences.get(this.changeID.getActorID()!)!), @@ -1357,16 +1380,13 @@ export class Document { } const change = context.getChange(); - try { - change.execute(this.clone!.root, this.clone!.presences); - } catch (err) { - // drop clone because it is contaminated. - this.clone = undefined; - logger.error(err); - throw err; - } + change.execute(this.clone!.root, this.clone!.presences, OpSource.UndoRedo); - const { opInfos, reverseOps } = change.execute(this.root, this.presences); + const { opInfos, reverseOps } = change.execute( + this.root, + this.presences, + OpSource.UndoRedo, + ); const reversePresence = context.getReversePresence(); if (reversePresence) { reverseOps.push({ @@ -1378,11 +1398,18 @@ export class Document { this.internalHistory.pushUndo(reverseOps); } - this.localChanges.push(change); - this.changeID = change.getID(); + // NOTE(chacha912): When there is no applied operation or presence + // during undo/redo, skip propagating change remotely. + if (change.hasPresenceChange() || opInfos.length > 0) { + this.localChanges.push(change); + } + this.changeID = change.getID(); const actorID = this.changeID.getActorID()!; - if (change.hasOperations()) { + // NOTE(chacha912): Although operations are included in the change, they + // may not be executable (e.g., when the target element has been deleted). + // So we check opInfos, which represent the actually executed operations. + if (opInfos.length > 0) { this.publish({ type: DocEventType.LocalChange, value: { @@ -1406,14 +1433,14 @@ export class Document { /** * `getUndoStackForTest` returns the undo stack for test. */ - public getUndoStackForTest(): Array> { + public getUndoStackForTest(): Array>> { return this.internalHistory.getUndoStackForTest(); } /** * `getRedoStackForTest` returns the redo stack for test. */ - public getRedoStackForTest(): Array> { + public getRedoStackForTest(): Array>> { return this.internalHistory.getRedoStackForTest(); } } diff --git a/src/document/history.ts b/src/document/history.ts index ad99b40bd..bc5fc063d 100644 --- a/src/document/history.ts +++ b/src/document/history.ts @@ -96,22 +96,14 @@ export class History

{ /** * `getUndoStackForTest` returns the undo stack for test. */ - public getUndoStackForTest(): Array> { - return this.undoStack.map((ops) => - ops.map((op) => { - return op instanceof Operation ? op.toTestString() : JSON.stringify(op); - }), - ); + public getUndoStackForTest(): Array>> { + return this.undoStack; } /** * `getRedoStackForTest` returns the redo stack for test. */ - public getRedoStackForTest(): Array> { - return this.redoStack.map((ops) => - ops.map((op) => { - return op instanceof Operation ? op.toTestString() : JSON.stringify(op); - }), - ); + public getRedoStackForTest(): Array>> { + return this.redoStack; } } diff --git a/src/document/json/array.ts b/src/document/json/array.ts index b449f4f65..b8e45b1d2 100644 --- a/src/document/json/array.ts +++ b/src/document/json/array.ts @@ -171,11 +171,15 @@ export class ArrayProxy { }; } else if (method === 'getElementByID') { return (createdAt: TimeTicket): WrappedElement | undefined => { - return toWrappedElement(context, target.get(createdAt)); + const elem = target.getByID(createdAt); + if (!elem || elem.isRemoved()) { + return; + } + return toWrappedElement(context, elem); }; } else if (method === 'getElementByIndex') { return (index: number): WrappedElement | undefined => { - const elem = target.getByIndex(index); + const elem = target.get(index); return toWrappedElement(context, elem); }; } else if (method === 'getLast') { @@ -235,10 +239,7 @@ export class ArrayProxy { ArrayProxy.moveLastInternal(context, target, id); }; } else if (isNumericString(method)) { - return toJSONElement( - context, - target.getByIndex(Number(method as string)), - ); + return toJSONElement(context, target.get(Number(method as string))); } else if (method === 'push') { return (value: any): number => { return ArrayProxy.pushInternal(context, target, value); @@ -448,7 +449,7 @@ export class ArrayProxy { AddOperation.create( target.getCreatedAt(), prevCreatedAt, - primitive, + primitive.deepcopy(), ticket, ), ); @@ -462,7 +463,7 @@ export class ArrayProxy { AddOperation.create( target.getCreatedAt(), prevCreatedAt, - array, + array.deepcopy(), ticket, ), ); @@ -475,7 +476,12 @@ export class ArrayProxy { target.insertAfter(prevCreatedAt, obj); context.registerElement(obj, target); context.push( - AddOperation.create(target.getCreatedAt(), prevCreatedAt, obj, ticket), + AddOperation.create( + target.getCreatedAt(), + prevCreatedAt, + obj.deepcopy(), + ticket, + ), ); for (const [k, v] of Object.entries(value!)) { @@ -578,9 +584,7 @@ export class ArrayProxy { } if (items) { let previousID = - from === 0 - ? target.getHead().getID() - : target.getByIndex(from - 1)!.getID(); + from === 0 ? target.getHead().getID() : target.get(from - 1)!.getID(); for (const item of items) { const newElem = ArrayProxy.insertAfterInternal( context, @@ -622,8 +626,7 @@ export class ArrayProxy { for (let i = from; i < length; i++) { if ( - target.getByIndex(i)?.getID() === - (searchElement as WrappedElement).getID!() + target.get(i)?.getID() === (searchElement as WrappedElement).getID!() ) { return true; } @@ -659,8 +662,7 @@ export class ArrayProxy { for (let i = from; i < length; i++) { if ( - target.getByIndex(i)?.getID() === - (searchElement as WrappedElement).getID!() + target.get(i)?.getID() === (searchElement as WrappedElement).getID!() ) { return i; } @@ -696,8 +698,7 @@ export class ArrayProxy { for (let i = from; i > 0; i--) { if ( - target.getByIndex(i)?.getID() === - (searchElement as WrappedElement).getID!() + target.get(i)?.getID() === (searchElement as WrappedElement).getID!() ) { return i; } diff --git a/src/document/json/object.ts b/src/document/json/object.ts index 4fc8ed2cb..8755b65ee 100644 --- a/src/document/json/object.ts +++ b/src/document/json/object.ts @@ -108,6 +108,10 @@ export class ObjectProxy { return (): object => { return target.toJS(); }; + } else if (keyOrMethod === 'toJSForTest') { + return (): object => { + return target.toJSForTest(); + }; } return toJSONElement(context, target.get(keyOrMethod)); @@ -154,7 +158,7 @@ export class ObjectProxy { const ticket = context.issueTimeTicket(); const setAndRegister = function (elem: CRDTElement) { - const removed = target.set(key, elem); + const removed = target.set(key, elem, ticket); context.registerElement(elem, target); if (removed) { context.registerRemovedElement(removed); @@ -184,7 +188,7 @@ export class ObjectProxy { } else if (typeof value === 'object') { if (value instanceof Text) { const text = CRDTText.create(RGATreeSplit.create(), ticket); - target.set(key, text); + target.set(key, text, ticket); context.registerElement(text, target); context.push( SetOperation.create( @@ -201,7 +205,7 @@ export class ObjectProxy { value.getValue(), ticket, ); - target.set(key, counter); + target.set(key, counter, ticket); context.registerElement(counter, target); context.push( SetOperation.create( @@ -214,7 +218,7 @@ export class ObjectProxy { value.initialize(context, counter); } else if (value instanceof Tree) { const tree = CRDTTree.create(value.buildRoot(context), ticket); - target.set(key, tree); + target.set(key, tree, ticket); context.registerElement(tree, target); context.push( SetOperation.create( diff --git a/src/document/operation/increase_operation.ts b/src/document/operation/increase_operation.ts index 24ae16a0c..d606f271b 100644 --- a/src/document/operation/increase_operation.ts +++ b/src/document/operation/increase_operation.ts @@ -78,14 +78,14 @@ export class IncreaseOperation extends Operation { value: value.getValue() as number, }, ], - reverseOp: this.getReverseOperation(), + reverseOp: this.toReverseOperation(), }; } /** - * `getReverseOperation` returns the reverse operation of this operation. + * `toReverseOperation` returns the reverse operation of this operation. */ - public getReverseOperation(): Operation { + private toReverseOperation(): Operation { const primitiveValue = this.value.deepcopy() as Primitive; const valueType = primitiveValue.getType(); diff --git a/src/document/operation/operation.ts b/src/document/operation/operation.ts index 525b7d241..3b246645b 100644 --- a/src/document/operation/operation.ts +++ b/src/document/operation/operation.ts @@ -20,6 +20,17 @@ import { TreeNode } from '@yorkie-js-sdk/src/document/crdt/tree'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { Indexable } from '@yorkie-js-sdk/src/document/document'; +/** + * `OpSource` represents the source of the operation. It is used to handle + * corner cases in the operations created by undo/redo allow the removed + * elements when executing them. + */ +export enum OpSource { + Local = 'local', + Remote = 'remote', + UndoRedo = 'undoredo', +} + /** * `OperationInfo` represents the information of an operation. * It is used to inform to the user what kind of operation was executed. @@ -189,10 +200,14 @@ export abstract class Operation { /** * `getExecutedAt` returns execution time of this operation. */ - // TODO(Hyemmie): Corner cases need to be considered: undo/redo operations' - // `executedAt` could be undefined until they are executed. public getExecutedAt(): TimeTicket { - return this.executedAt!; + // NOTE(chacha912): When an operation is in the undo/redo stack, + // it doesn't have an executedAt yet. The executedAt is set when + // the operation is executed through undo or redo. + if (!this.executedAt) { + throw new Error(`executedAt has not been set yet`); + } + return this.executedAt; } /** @@ -224,5 +239,8 @@ export abstract class Operation { /** * `execute` executes this operation on the given `CRDTRoot`. */ - public abstract execute(root: CRDTRoot): ExecutionResult; + public abstract execute( + root: CRDTRoot, + source: OpSource, + ): ExecutionResult | undefined; } diff --git a/src/document/operation/remove_operation.ts b/src/document/operation/remove_operation.ts index 9255ccd8b..49c41bee3 100644 --- a/src/document/operation/remove_operation.ts +++ b/src/document/operation/remove_operation.ts @@ -18,12 +18,15 @@ import { logger } from '@yorkie-js-sdk/src/util/logger'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { + OpSource, Operation, OperationInfo, ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; import { CRDTContainer } from '@yorkie-js-sdk/src/document/crdt/element'; +import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; +import { SetOperation } from '@yorkie-js-sdk/src/document/operation/set_operation'; /** * `RemoveOperation` is an operation that removes an element from `CRDTContainer`. @@ -34,7 +37,7 @@ export class RemoveOperation extends Operation { constructor( parentCreatedAt: TimeTicket, createdAt: TimeTicket, - executedAt: TimeTicket, + executedAt?: TimeTicket, ) { super(parentCreatedAt, executedAt); this.createdAt = createdAt; @@ -46,7 +49,7 @@ export class RemoveOperation extends Operation { public static create( parentCreatedAt: TimeTicket, createdAt: TimeTicket, - executedAt: TimeTicket, + executedAt?: TimeTicket, ): RemoveOperation { return new RemoveOperation(parentCreatedAt, createdAt, executedAt); } @@ -54,17 +57,32 @@ export class RemoveOperation extends Operation { /** * `execute` executes this operation on the given `CRDTRoot`. */ - public execute(root: CRDTRoot): ExecutionResult { - const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); + public execute( + root: CRDTRoot, + source: OpSource, + ): ExecutionResult | undefined { + const parentObject = root.findByCreatedAt( + this.getParentCreatedAt(), + ) as CRDTContainer; if (!parentObject) { logger.fatal(`fail to find ${this.getParentCreatedAt()}`); } if (!(parentObject instanceof CRDTContainer)) { logger.fatal(`only object and array can execute remove: ${parentObject}`); } - const obj = parentObject as CRDTContainer; - const key = obj.subPathOf(this.createdAt); - const elem = obj.delete(this.createdAt, this.getExecutedAt()); + + // NOTE(chacha912): Handle cases where operation cannot be executed during undo and redo. + const targetElem = parentObject.getByID(this.createdAt); + if ( + source === OpSource.UndoRedo && + (parentObject.getRemovedAt() || !targetElem || targetElem.isRemoved()) + ) { + return; + } + const key = parentObject.subPathOf(this.createdAt); + const reverseOp = this.toReverseOperation(parentObject); + + const elem = parentObject.delete(this.createdAt, this.getExecutedAt()); root.registerRemovedElement(elem); const opInfos: Array = @@ -84,7 +102,29 @@ export class RemoveOperation extends Operation { }, ]; - return { opInfos }; + return { opInfos, reverseOp }; + } + + /** + * `toReverseOperation` returns the reverse operation of this operation. + */ + private toReverseOperation( + parentObject: CRDTContainer, + ): Operation | undefined { + // TODO(Hyemmie): consider CRDTArray + if (parentObject instanceof CRDTObject) { + const key = parentObject.subPathOf(this.createdAt); + if (key !== undefined) { + const value = parentObject.get(key); + if (value !== undefined) { + return SetOperation.create( + key, + value.deepcopy(), + this.getParentCreatedAt(), + ); + } + } + } } /** @@ -98,7 +138,7 @@ export class RemoveOperation extends Operation { * `toTestString` returns a string containing the meta data. */ public toTestString(): string { - return `${this.getParentCreatedAt().toTestString()}.REMOVE`; + return `${this.getParentCreatedAt().toTestString()}.REMOVE.${this.createdAt.toTestString()}`; } /** diff --git a/src/document/operation/set_operation.ts b/src/document/operation/set_operation.ts index 88884ff44..74ae9eb91 100644 --- a/src/document/operation/set_operation.ts +++ b/src/document/operation/set_operation.ts @@ -20,9 +20,11 @@ import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTRoot } from '@yorkie-js-sdk/src/document/crdt/root'; import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { + OpSource, Operation, ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; +import { RemoveOperation } from '@yorkie-js-sdk/src/document/operation/remove_operation'; /** * `SetOperation` represents an operation that stores the value corresponding to the @@ -36,7 +38,7 @@ export class SetOperation extends Operation { key: string, value: CRDTElement, parentCreatedAt: TimeTicket, - executedAt: TimeTicket, + executedAt?: TimeTicket, ) { super(parentCreatedAt, executedAt); this.key = key; @@ -50,7 +52,7 @@ export class SetOperation extends Operation { key: string, value: CRDTElement, parentCreatedAt: TimeTicket, - executedAt: TimeTicket, + executedAt?: TimeTicket, ): SetOperation { return new SetOperation(key, value, parentCreatedAt, executedAt); } @@ -58,7 +60,10 @@ export class SetOperation extends Operation { /** * `execute` executes this operation on the given `CRDTRoot`. */ - public execute(root: CRDTRoot): ExecutionResult { + public execute( + root: CRDTRoot, + source: OpSource, + ): ExecutionResult | undefined { const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); if (!parentObject) { logger.fatal(`fail to find ${this.getParentCreatedAt()}`); @@ -67,8 +72,15 @@ export class SetOperation extends Operation { logger.fatal(`fail to execute, only object can execute set`); } const obj = parentObject as CRDTObject; + // NOTE(chacha912): Handle cases where operation cannot be executed during undo and redo. + if (source === OpSource.UndoRedo && obj.getRemovedAt()) { + return; + } + const previousValue = obj.get(this.key); + const reverseOp = this.toReverseOperation(previousValue); + const value = this.value.deepcopy(); - const removed = obj.set(this.key, value); + const removed = obj.set(this.key, value, this.getExecutedAt()); root.registerElement(value, obj); if (removed) { root.registerRemovedElement(removed); @@ -82,9 +94,32 @@ export class SetOperation extends Operation { key: this.key, }, ], + reverseOp, }; } + /** + * `toReverseOperation` returns the reverse operation of this operation. + */ + private toReverseOperation(value: CRDTElement | undefined): Operation { + let reverseOp: SetOperation | RemoveOperation = RemoveOperation.create( + this.getParentCreatedAt(), + this.value.getCreatedAt(), + ); + + if (value !== undefined && !value.isRemoved()) { + // TODO(chacha912): When the value is an object, + // it always sets as an empty object from the remote. + // (Refer to https://github.com/yorkie-team/yorkie/issues/663) + reverseOp = SetOperation.create( + this.key, + value.deepcopy(), + this.getParentCreatedAt(), + ); + } + return reverseOp; + } + /** * `getEffectedCreatedAt` returns the creation time of the effected element. */ @@ -96,7 +131,9 @@ export class SetOperation extends Operation { * `toTestString` returns a string containing the meta data. */ public toTestString(): string { - return `${this.getParentCreatedAt().toTestString()}.SET`; + return `${this.getParentCreatedAt().toTestString()}.SET.${ + this.key + }=${this.value.toSortedJSON()}`; } /** diff --git a/src/types/devtools_element.ts b/src/types/devtools_element.ts new file mode 100644 index 000000000..6e87f4d9d --- /dev/null +++ b/src/types/devtools_element.ts @@ -0,0 +1,38 @@ +import type { PrimitiveValue } from '@yorkie-js-sdk/src/document/crdt/primitive'; +import { CounterValue } from '@yorkie-js-sdk/src/document/crdt/counter'; + +// NOTE(chacha912): Json type is used to represent CRDTText and CRDTTree value. +// In the dev tool, display value as the result of toJSON for CRDTText and CRDTTree. +export type Json = + | string + | number + | boolean + // eslint-disable-next-line @typescript-eslint/ban-types + | null + | { [key: string]: Json } + | Array; + +export type ContainerValue = { + [key: string]: JSONElement; +}; + +type ElementValue = + | PrimitiveValue + | CounterValue + | ContainerValue // Array | Object + | Json; // Text | Tree + +export type ElementType = + | 'YORKIE_PRIMITIVE' + | 'YORKIE_COUNTER' + | 'YORKIE_OBJECT' + | 'YORKIE_ARRAY' + | 'YORKIE_TEXT' + | 'YORKIE_TREE'; + +export type JSONElement = { + id: string; + key?: string; + value: ElementValue; + type: ElementType; +}; diff --git a/test/helper/helper.ts b/test/helper/helper.ts index 5b89c8890..2c3e722e6 100644 --- a/test/helper/helper.ts +++ b/test/helper/helper.ts @@ -19,7 +19,11 @@ import { assert } from 'chai'; import yorkie, { Tree, ElementNode } from '@yorkie-js-sdk/src/yorkie'; import { IndexTree } from '@yorkie-js-sdk/src/util/index_tree'; import { CRDTTreeNode } from '@yorkie-js-sdk/src/document/crdt/tree'; -import { OperationInfo } from '@yorkie-js-sdk/src/document/operation/operation'; +import { + OperationInfo, + Operation, +} from '@yorkie-js-sdk/src/document/operation/operation'; +import { HistoryOperation } from '@yorkie-js-sdk/src/document/history'; export type Indexable = Record; @@ -228,3 +232,9 @@ export function buildIndexTree(node: ElementNode): IndexTree { }); return doc.getRoot().t.getIndexTree(); } + +export function toStringHistoryOp

( + op: HistoryOperation

, +): string { + return op instanceof Operation ? op.toTestString() : JSON.stringify(op); +} diff --git a/test/integration/counter_test.ts b/test/integration/counter_test.ts index 7aad05e98..3f8d04af2 100644 --- a/test/integration/counter_test.ts +++ b/test/integration/counter_test.ts @@ -1,5 +1,6 @@ import { describe, it, assert } from 'vitest'; import { Document } from '@yorkie-js-sdk/src/document/document'; +import { toStringHistoryOp } from '@yorkie-js-sdk/test/helper/helper'; import { withTwoClientsAndDocuments, assertUndoRedo, @@ -147,17 +148,18 @@ describe('Counter', function () { root.longCnt.increase(Long.fromString('9223372036854775807')); // 2^63-1 }); assert.equal(doc.toSortedJSON(), `{"cnt":1,"longCnt":9223372036854775807}`); - assert.equal( - JSON.stringify(doc.getUndoStackForTest()), - `[["1:00:2.INCREASE.-9223372036854775807","1:00:1.INCREASE.-1.5"]]`, - ); + + assert.deepEqual(doc.getUndoStackForTest().at(-1)?.map(toStringHistoryOp), [ + '1:00:2.INCREASE.-9223372036854775807', + '1:00:1.INCREASE.-1.5', + ]); doc.history.undo(); assert.equal(doc.toSortedJSON(), `{"cnt":0,"longCnt":0}`); - assert.equal( - JSON.stringify(doc.getRedoStackForTest()), - `[["1:00:1.INCREASE.1.5","1:00:2.INCREASE.9223372036854775807"]]`, - ); + assert.deepEqual(doc.getRedoStackForTest().at(-1)?.map(toStringHistoryOp), [ + '1:00:1.INCREASE.1.5', + '1:00:2.INCREASE.9223372036854775807', + ]); }); it('Can undo/redo for increase operation', async function ({ task }) { diff --git a/test/integration/document_test.ts b/test/integration/document_test.ts index 0e97e5384..b885c8940 100644 --- a/test/integration/document_test.ts +++ b/test/integration/document_test.ts @@ -745,7 +745,7 @@ describe('Document', function () { }, 'init counter'); assert.equal(doc.toSortedJSON(), '{"counter":100}'); - assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canUndo(), true); assert.equal(doc.history.canRedo(), false); // user increases the counter @@ -760,7 +760,7 @@ describe('Document', function () { // user undoes the latest operation doc.history.undo(); - assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canUndo(), true); assert.equal(doc.history.canRedo(), true); // user redoes the latest undone operation @@ -779,7 +779,7 @@ describe('Document', function () { }, 'init counter'); assert.equal(doc.toSortedJSON(), '{"counter":100}'); - assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canUndo(), true); assert.equal(doc.history.canRedo(), false); for (let i = 0; i < 5; i++) { @@ -839,7 +839,7 @@ describe('Document', function () { }, 'init counter'); assert.equal(doc.toSortedJSON(), '{"counter":100}'); - assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canUndo(), true); assert.equal(doc.history.canRedo(), false); assert.throws( @@ -872,7 +872,7 @@ describe('Document', function () { }, 'init counter'); assert.equal(doc.toSortedJSON(), '{"counter":0}'); - assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canUndo(), true); assert.equal(doc.history.canRedo(), false); for (let i = 0; i < 100; i++) { diff --git a/test/integration/object_test.ts b/test/integration/object_test.ts index fafeba262..666f61658 100644 --- a/test/integration/object_test.ts +++ b/test/integration/object_test.ts @@ -1,7 +1,13 @@ import { describe, it, assert } from 'vitest'; -import { JSONObject } from '@yorkie-js-sdk/src/yorkie'; +import { JSONObject, Client } from '@yorkie-js-sdk/src/yorkie'; import { Document } from '@yorkie-js-sdk/src/document/document'; -import { withTwoClientsAndDocuments } from '@yorkie-js-sdk/test/integration/integration_helper'; +import { + withTwoClientsAndDocuments, + assertUndoRedo, + toDocKey, + testRPCAddr, +} from '@yorkie-js-sdk/test/integration/integration_helper'; +import { toStringHistoryOp } from '@yorkie-js-sdk/test/helper/helper'; import { YorkieError } from '@yorkie-js-sdk/src/util/error'; describe('Object', function () { @@ -80,24 +86,31 @@ describe('Object', function () { '{"k1":{"k1-1":"v1","k1-2":"v3"},"k2":["1","2","3","4",{"k2-5":"v4"}]}', doc.toSortedJSON(), ); + + // TODO(Hyemmie): test assertUndoRedo after implementing array's reverse operation }); it('should handle delete operations', function () { const doc = new Document<{ k1: { 'k1-1'?: string; 'k1-2': string; 'k1-3'?: string }; }>('test-doc'); + const states: Array = []; assert.equal('{}', doc.toSortedJSON()); doc.update((root) => { root['k1'] = { 'k1-1': 'v1', 'k1-2': 'v2' }; }, 'set {"k1":{"k1-1":"v1","k1-2":"v2"}}'); assert.equal('{"k1":{"k1-1":"v1","k1-2":"v2"}}', doc.toSortedJSON()); + states.push(doc.toSortedJSON()); doc.update((root) => { delete root['k1']['k1-1']; root['k1']['k1-3'] = 'v4'; }, 'set {"k1":{"k1-2":"v2"}}'); assert.equal('{"k1":{"k1-2":"v2","k1-3":"v4"}}', doc.toSortedJSON()); + states.push(doc.toSortedJSON()); + + assertUndoRedo(doc, states); }); it('should support toJS and toJSON methods', function () { @@ -192,4 +205,463 @@ describe('Object', function () { assert.equal(d1.toSortedJSON(), d2.toSortedJSON()); }, task.name); }); + + it('Returns undefined when looking up an element that doesnt exist', function () { + const doc = new Document<{ + shapes: { + [key: string]: { color: string; point: { x: number; y: number } }; + }; + }>('test-doc'); + assert.equal('{}', doc.toSortedJSON()); + + doc.update((root) => { + root.shapes = { + circle: { color: 'black', point: { x: 0, y: 0 } }, + }; + }); + assert.equal( + '{"shapes":{"circle":{"color":"black","point":{"x":0,"y":0}}}}', + doc.toSortedJSON(), + ); + + doc.update((root) => { + delete root.shapes.circle; + }); + assert.equal('{"shapes":{}}', doc.toSortedJSON()); + assert.isUndefined(doc.getRoot().shapes.circle); + assert.isUndefined(doc.getRoot().shapes.circle?.color); + assert.isUndefined(doc.getRoot().shapes.circle?.point); + assert.isUndefined(doc.getRoot().shapes.circle?.point?.x); + }); + + describe('Undo/Redo', function () { + it('can get proper reverse operations', function () { + const doc = new Document<{ + shape: { color: string }; + }>('test-doc'); + + doc.update((root) => { + root.shape = { color: 'black' }; + }); + assert.equal(doc.toSortedJSON(), '{"shape":{"color":"black"}}'); + assert.deepEqual( + doc.getUndoStackForTest().at(-1)?.map(toStringHistoryOp), + ['1:00:1.REMOVE.1:00:2', '0:00:0.REMOVE.1:00:1'], + ); + + doc.history.undo(); + assert.equal(doc.toSortedJSON(), `{}`); + assert.deepEqual( + doc.getRedoStackForTest().at(-1)?.map(toStringHistoryOp), + ['0:00:0.SET.shape={"color":"black"}', '1:00:1.SET.color="black"'], + ); + + doc.history.redo(); + assert.equal(doc.toSortedJSON(), '{"shape":{"color":"black"}}'); + doc.update((root) => { + root.shape.color = 'red'; + }); + assert.equal(doc.toSortedJSON(), '{"shape":{"color":"red"}}'); + assert.deepEqual( + doc.getUndoStackForTest().at(-1)?.map(toStringHistoryOp), + ['1:00:1.SET.color="black"'], + ); + + doc.history.undo(); + assert.equal(doc.toSortedJSON(), '{"shape":{"color":"black"}}'); + assert.deepEqual( + doc.getRedoStackForTest().at(-1)?.map(toStringHistoryOp), + ['1:00:1.SET.color="red"'], + ); + + doc.history.redo(); + assert.equal(doc.toSortedJSON(), '{"shape":{"color":"red"}}'); + }); + + it('Can undo/redo work properly for simple object', function () { + const doc = new Document<{ + a: number; + }>('test-doc'); + assert.equal(doc.toSortedJSON(), '{}'); + assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canRedo(), false); + + doc.update((root) => { + root.a = 1; + }); + assert.equal(doc.toSortedJSON(), '{"a":1}'); + assert.equal(doc.history.canUndo(), true); + assert.equal(doc.history.canRedo(), false); + + doc.update((root) => { + root.a = 2; + }); + assert.equal(doc.toSortedJSON(), '{"a":2}'); + assert.equal(doc.history.canUndo(), true); + assert.equal(doc.history.canRedo(), false); + + doc.history.undo(); + assert.equal(doc.toSortedJSON(), '{"a":1}'); + assert.equal(doc.history.canUndo(), true); + assert.equal(doc.history.canRedo(), true); + + doc.history.redo(); + assert.equal(doc.toSortedJSON(), '{"a":2}'); + assert.equal(doc.history.canUndo(), true); + assert.equal(doc.history.canRedo(), false); + + doc.history.undo(); + assert.equal(doc.toSortedJSON(), '{"a":1}'); + assert.equal(doc.history.canUndo(), true); + assert.equal(doc.history.canRedo(), true); + + doc.history.undo(); + assert.equal(doc.toSortedJSON(), '{}'); + assert.equal(doc.history.canUndo(), false); + assert.equal(doc.history.canRedo(), true); + }); + + it('Can undo/redo work properly for nested object', function () { + const doc = new Document<{ + shape: { point: { x: number; y: number }; color: string }; + a: number; + }>('test-doc'); + const states: Array = []; + states.push(doc.toSortedJSON()); + assert.equal(doc.toSortedJSON(), '{}'); + + doc.update((root) => { + root.shape = { point: { x: 0, y: 0 }, color: 'red' }; + root.a = 0; + }); + states.push(doc.toSortedJSON()); + assert.equal( + doc.toSortedJSON(), + '{"a":0,"shape":{"color":"red","point":{"x":0,"y":0}}}', + ); + + doc.update((root) => { + root.shape.point = { x: 1, y: 1 }; + root.shape.color = 'blue'; + }); + states.push(doc.toSortedJSON()); + assert.equal( + doc.toSortedJSON(), + '{"a":0,"shape":{"color":"blue","point":{"x":1,"y":1}}}', + ); + + doc.update((root) => { + root.a = 1; + root.a = 2; + }); + states.push(doc.toSortedJSON()); + assert.equal( + doc.toSortedJSON(), + '{"a":2,"shape":{"color":"blue","point":{"x":1,"y":1}}}', + ); + + assertUndoRedo(doc, states); + }); + + it.skip(`Should ensure convergence of peer's document after undoing nested objects`, async function ({ + task, + }) { + // Test scenario: + // c1: set shape.point to {x: 0, y: 0} + // c1: set shape.point to {x: 1, y: 1} + // c1: undo + interface TestDoc { + shape?: { point: { x: number; y: number } }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + doc1.update((root) => { + root.shape = { point: { x: 0, y: 0 } }; + }); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal(doc2.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); + + doc1.update((root) => { + root.shape!.point = { x: 1, y: 1 }; + }); + await client1.sync(); + await client2.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"point":{"x":1,"y":1}}}'); + assert.equal(doc2.toSortedJSON(), '{"shape":{"point":{"x":1,"y":1}}}'); + + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); + await client1.sync(); + await client2.sync(); + // TODO(chacha912): fix test + assert.equal(doc2.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); // as-is: {"shape":{"point":{}}} + }); + + it(`Should handle reverse (set) operation targeting elements deleted by other peers`, async function ({ + task, + }) { + // Test scenario: + // c1: set shape.color to 'red' + // c2: delete shape + // c1: undo(no changes as the shape was deleted) + interface TestDoc { + shape?: { color: string }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + doc1.update((root) => { + root.shape = { color: 'black' }; + }, 'init doc'); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"black"}}'); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"black"}}'); + + doc1.update((root) => { + root.shape!.color = 'red'; + }, 'set red'); + await client1.sync(); + await client2.sync(); + doc2.update((root) => { + delete root.shape; + }, 'delete shape'); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc2.toSortedJSON(), '{}'); + + // c2 deleted the shape, so the reverse operation cannot be applied + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc1.getRedoStackForTest().length, 0); + assert.equal(doc1.history.canRedo(), false); + await client1.sync(); + await client2.sync(); + await client1.sync(); + }); + + it(`Should handle reverse (remove) operation targeting elements deleted by other peers`, async function ({ + task, + }) { + // Test scenario: + // c1: create shape + // c2: delete shape + // c1: undo(no changes as the shape was deleted) + interface TestDoc { + shape?: { color: string }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + doc1.update((root) => { + root.shape = { color: 'black' }; + }, 'init doc'); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"black"}}'); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"black"}}'); + + doc2.update((root) => { + delete root.shape; + }, 'delete shape'); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc2.toSortedJSON(), '{}'); + + // c2 deleted the shape, so the reverse operation cannot be applied + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc1.getRedoStackForTest().length, 0); + assert.equal(doc1.history.canRedo(), false); + await client1.sync(); + await client2.sync(); + await client1.sync(); + }); + + it('Can handle concurrent undo/redo: local undo & global redo', async function ({ + task, + }) { + interface TestDoc { + color: string; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + await client2.attach(doc2, { isRealtimeSync: false }); + doc1.update((root) => { + root.color = 'black'; + }, 'init doc'); + await client1.sync(); + await client2.sync(); + assert.equal(doc1.toSortedJSON(), '{"color":"black"}'); + assert.equal(doc2.toSortedJSON(), '{"color":"black"}'); + + doc1.update((root) => { + root.color = 'red'; + }, 'set red'); + doc2.update((root) => { + root.color = 'green'; + }, 'set green'); + await client1.sync(); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"color":"green"}'); + assert.equal(doc2.toSortedJSON(), '{"color":"green"}'); + + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{"color":"black"}'); // local-undo + await client1.sync(); + await client2.sync(); + assert.equal(doc2.toSortedJSON(), '{"color":"black"}'); + + doc1.history.redo(); + assert.equal(doc1.toSortedJSON(), '{"color":"green"}'); // global-redo + await client1.sync(); + await client2.sync(); + assert.equal(doc2.toSortedJSON(), '{"color":"green"}'); + }); + + it('Can properly apply remote operations that occurred before local undo', async function ({ + task, + }) { + // Test scenario: + // c1 & c2: color='black' + // c1: set color to 'red' + // c2: set color to 'green' + // c1: undo + // sync c1 & c2 + interface TestDoc { + color: string; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey, { disableGC: true }); + const doc2 = new Document(docKey, { disableGC: true }); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + await client2.attach(doc2, { isRealtimeSync: false }); + doc1.update((root) => { + root.color = 'black'; + }, 'init doc'); + await client1.sync(); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"color":"black"}'); + assert.equal(doc2.toSortedJSON(), '{"color":"black"}'); + + doc1.update((root) => { + root.color = 'red'; + }, 'set red'); + doc2.update((root) => { + root.color = 'green'; + }, 'set green'); + + assert.equal(doc1.toSortedJSON(), '{"color":"red"}'); + assert.equal(doc2.toSortedJSON(), '{"color":"green"}'); + + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{"color":"black"}'); + + await client1.sync(); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"color":"black"}'); + assert.equal(doc2.toSortedJSON(), '{"color":"black"}'); + + doc1.history.redo(); + await client1.sync(); + await client2.sync(); + assert.equal(doc1.toSortedJSON(), '{"color":"red"}'); + assert.equal(doc2.toSortedJSON(), '{"color":"red"}'); + }); + + it(`Should handle case of reverse operations referencing already garbage-collected elements`, async function ({ + task, + }) { + interface TestDoc { + shape: { color: string }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + // TODO(chacha912): Remove the disableGC option + const doc1 = new Document(docKey, { disableGC: true }); + const doc2 = new Document(docKey, { disableGC: true }); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + await client2.attach(doc2, { isRealtimeSync: false }); + + doc1.update((root) => { + root.shape = { color: 'black' }; + }); + doc2.update((root) => { + root.shape = { color: 'yellow' }; + }); + await client1.sync(); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"yellow"}}'); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"yellow"}}'); + + doc2.update((root) => { + root.shape.color = 'red'; + }); + await client2.sync(); + await client1.sync(); + await client2.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"red"}}'); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"red"}}'); + + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"red"}}'); + assert.equal(doc1.getRedoStackForTest().length, 0); + assert.equal(doc1.history.canRedo(), false); + await client1.sync(); + await client2.sync(); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"red"}}'); + }); + }); }); diff --git a/test/integration/presence_test.ts b/test/integration/presence_test.ts index 4c19736f5..c45f2dc41 100644 --- a/test/integration/presence_test.ts +++ b/test/integration/presence_test.ts @@ -632,10 +632,10 @@ describe('Undo/Redo', function () { }); assert.deepEqual(doc.getUndoStackForTest(), [ [ - JSON.stringify({ + { type: 'presence', value: { color: 'red', cursor: { x: 0, y: 0 } }, - }), + }, ], ]); @@ -662,16 +662,16 @@ describe('Undo/Redo', function () { }); assert.deepEqual(doc.getUndoStackForTest(), [ [ - JSON.stringify({ + { type: 'presence', value: { color: 'red', cursor: { x: 0, y: 0 } }, - }), + }, ], [ - JSON.stringify({ + { type: 'presence', value: { cursor: { x: 1, y: 1 } }, - }), + }, ], ]); @@ -698,16 +698,16 @@ describe('Undo/Redo', function () { }); assert.deepEqual(doc.getUndoStackForTest(), [ [ - JSON.stringify({ + { type: 'presence', value: { color: 'red', cursor: { x: 0, y: 0 } }, - }), + }, ], [ - JSON.stringify({ + { type: 'presence', value: { cursor: { x: 1, y: 1 } }, - }), + }, ], ]); diff --git a/test/unit/document/crdt/root_test.ts b/test/unit/document/crdt/root_test.ts index d64f7245a..6e94776a0 100644 --- a/test/unit/document/crdt/root_test.ts +++ b/test/unit/document/crdt/root_test.ts @@ -24,8 +24,9 @@ describe('ROOT', function () { assert.equal(root.createPath(MaxTimeTicket), ''); // set '$.k1' - const k1 = Primitive.of('k1', cc.issueTimeTicket()); - root.getObject().set('k1', k1); + let ticket = cc.issueTimeTicket(); + const k1 = Primitive.of('k1', ticket); + root.getObject().set('k1', k1, ticket); root.registerElement(k1, root.getObject()); assert.equal(root.getElementMapSize(), 2); assert.equal(root.findByCreatedAt(k1.getCreatedAt()), k1); @@ -39,8 +40,9 @@ describe('ROOT', function () { assert.isUndefined(root.findByCreatedAt(k1.getCreatedAt())); // set '$.k2' - const k2 = CRDTObject.create(cc.issueTimeTicket()); - root.getObject().set('k2', k2); + ticket = cc.issueTimeTicket(); + const k2 = CRDTObject.create(ticket); + root.getObject().set('k2', k2, ticket); root.registerElement(k2, root.getObject()); assert.equal(root.getElementMapSize(), 2); assert.equal(root.findByCreatedAt(k2.getCreatedAt()), k2); @@ -49,8 +51,9 @@ describe('ROOT', function () { assert.equal(Object.keys(k2.toJS()).length, 0); // set '$.k2.1' - const k2Dot1 = CRDTArray.create(cc.issueTimeTicket()); - k2.set('1', k2Dot1); + ticket = cc.issueTimeTicket(); + const k2Dot1 = CRDTArray.create(ticket); + k2.set('1', k2Dot1, ticket); root.registerElement(k2Dot1, k2); assert.equal(root.getElementMapSize(), 3); assert.equal(root.findByCreatedAt(k2Dot1.getCreatedAt()), k2Dot1); @@ -90,7 +93,7 @@ describe('ROOT', function () { assert.equal(1, arrJs1?.[1]); assert.equal(2, arrJs1?.[2]); - const targetElement = arr.getByIndex(1)!; + const targetElement = arr.get(1)!; arr.delete(targetElement.getCreatedAt(), change.issueTimeTicket()); root.registerRemovedElement(targetElement); assert.equal('[0,2]', arr.toJSON()); @@ -110,11 +113,9 @@ describe('ROOT', function () { ); const obj = new CRDTObject(InitialTimeTicket, ElementRHT.create()); const change = ChangeContext.create(InitialChangeID, root, {}); - const crdtText = CRDTText.create( - RGATreeSplit.create(), - change.issueTimeTicket(), - ); - obj.set('k1', crdtText); + const executedAt = change.issueTimeTicket(); + const crdtText = CRDTText.create(RGATreeSplit.create(), executedAt); + obj.set('k1', crdtText, executedAt); change.registerElement(crdtText, obj); const text = new Text(change, crdtText); diff --git a/test/unit/document/document_test.ts b/test/unit/document/document_test.ts index ccdac7e8f..6a55df498 100644 --- a/test/unit/document/document_test.ts +++ b/test/unit/document/document_test.ts @@ -971,6 +971,17 @@ describe.sequential('Document', function () { { type: 'remove', path: '$', key: 'obj' }, ]); + doc.history.undo(); + await eventCollector.waitAndVerifyNthEvent(2, [ + { type: 'set', path: '$', key: 'obj' }, + { type: 'set', path: '$.obj', key: '$hello' }, + { type: 'remove', path: '$.obj', key: '$hello' }, + { type: 'set', path: '$.obj', key: 'a' }, + { type: 'remove', path: '$.obj', key: 'a' }, + { type: 'remove', path: '$', key: 'obj' }, + { type: 'remove', path: '$', key: '' }, + ]); + unsub(); }); From 0a5e977ff1a8184d4cdcc9323a9b8f2d37b6fb23 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 20 Nov 2023 18:01:03 +0900 Subject: [PATCH 02/48] Refactor ProseMirror example and Tree codes (#686) A. Refactor ProseMirror example This commit improves the ProseMirror example by removing redundant and unused code in both HTML and CSS, resulting in cleaner and simpler. B. Eliminate Tree.Split Since Tree.Split is invoked during content editing, this commit removes the separate Tree.Split, streamlining the codebase. C. Enhance Tree tests and uncomment basic text split test In preparation for adding a split parameter to Tree.Edit, this commit simplifies the Tree.Edit interface for better representation in a line. --- public/prosemirror.css | 137 +--- public/prosemirror.html | 187 ++--- src/document/crdt/tree.ts | 380 +++++----- src/document/json/tree.ts | 54 +- src/document/operation/tree_edit_operation.ts | 1 + test/integration/tree_test.ts | 6 +- test/unit/document/crdt/tree_test.ts | 651 +++++++----------- 7 files changed, 551 insertions(+), 865 deletions(-) diff --git a/public/prosemirror.css b/public/prosemirror.css index fc6a6a005..2a5e71659 100644 --- a/public/prosemirror.css +++ b/public/prosemirror.css @@ -8,9 +8,6 @@ body { .ProseMirror { position: relative; -} - -.ProseMirror { word-wrap: break-word; white-space: pre-wrap; white-space: break-spaces; @@ -234,6 +231,26 @@ img.ProseMirror-separator { animation: ProseMirror-cursor-blink 1.1s steps(2, start) infinite; } +.username-layer::before { + content: ''; + position: absolute; + width: 2px; + left: -1px; + background-color: currentColor; + bottom: -100%; + height: 100%; +} + +.username-layer.first-top::before { + content: ''; + position: absolute; + width: 2px; + left: -1px; + background-color: currentColor; + top: -100%; + height: 100%; +} + @keyframes ProseMirror-cursor-blink { to { visibility: hidden; @@ -404,52 +421,28 @@ img.ProseMirror-separator { .layout .application > * { flex: 1 1 auto; min-width: 0; - /* width: 50%; */ - border: 1px solid black; + border: 1px solid silver; padding: 10px; box-sizing: border-box; } .layout .application > .editor-area { - display: flex; gap: 20px; position: relative; } -.sub-log { - position: absolute; - bottom: 0px; - right: 0px; - left: 0px; - height: 100px; - background-color: rgb(255, 255, 198); -} - .layout .application > .editor-area > * { - flex: 1 1 auto; min-width: 0; - /* width: 50%; */ - /* border: 1px solid black; */ -} - -.layout .application > .editor-area > *:not(.sub-log):last-child { - width: 40%; - flex: none; } #app { - border: 1px solid silver; + border: 1px solid #c0c0c0; } .layout .log { - flex: none; + display: flex; height: 50%; overflow: auto; - border-top: 1px solid silver; - box-sizing: border-box; - padding: 0 10px; - display: flex; - gap: 10px; } .layout .log > * { @@ -501,25 +494,7 @@ img.ProseMirror-separator { font-size: 0.8em; } -#tr-log { - display: block; - align-items: center; - gap: 1px; - flex-wrap: wrap; -} - -#tr-log > * { - margin-right: 2px; - margin-bottom: 2px; -} - -.pm { - flex: none !important; - min-width: 300px; -} - .tr { - padding: 10px; flex: none !important; width: 300px; } @@ -535,78 +510,34 @@ img.ProseMirror-separator { flex: 1 1 auto; } -.tr-container > *:last-child { - flex: none; +.tr-container > *:first-child { height: 300px; - background-color: yellow; + background-color: #ddd; + padding: 10px; overflow: auto; } -.selection-item { - display: inline-flex; - align-items: center; - background-color: red; - color: white; - line-height: 0px; - padding: 4px 4px; - border-radius: 3px; - box-sizing: border-box; - width: 16px; - height: 16px; - vertical-align: middle; - align-items: center; - justify-content: center; - cursor: pointer; -} - .tr-item { line-height: 1; display: inline-block; - padding: 4px 4px; border-radius: 3px; box-sizing: border-box; width: 16px; height: 16px; text-align: center; - background-color: #444; - color: white; + color: #444; + border: 1px solid #444; vertical-align: middle; cursor: pointer; } -.data-view { - display: flex; - flex-direction: column; -} - -.tree-view { - flex: none; - height: 300px; - overflow: auto; - display: flex; -} - -.yorkie { - min-width: 300px; -} - -.list-view { - flex: 1 1 auto; -} - -.log-list-view { +.data-container { display: flex; - flex-wrap: wrap; -} - -.log-list-view .block { - border: 1px solid black; + flex-direction: row; } -.log-list-view .inline::before { - content: attr(data-id); - margin-right: 4px; - /* background-color: rgba(0, 0, 0, 0.2); */ - font-size: 0.8em; - /* color: white; */ +.data-item { + flex-grow: 1; + padding: 10px; + border-left: 1px solid silver; } diff --git a/public/prosemirror.html b/public/prosemirror.html index a8fcf8432..0295022d2 100644 --- a/public/prosemirror.html +++ b/public/prosemirror.html @@ -2,69 +2,37 @@ - Prosemirror Example + ProseMirror Example - -

-
-
-

Main

-
-
-
-
-

ProseMirror Doc

-
-
-
+

ProseMirror

+
-
-

Transaction

-
-
-
-
-
-
-
-
-

Yorkie.IndexTree

-
-
-
-

Yorkie.RGASplit

-
+
+
+

ProseMirror.Transaction

+
+
+
+ +
+

ProseMirror.Doc

+
+
+
+

Yorkie.Tree

+
+
@@ -74,7 +42,7 @@

Yorkie.RGASplit

"imports": { "prosemirror-state": "https://cdn.jsdelivr.net/npm/prosemirror-state@1.4.3/+esm", "prosemirror-view": "https://cdn.jsdelivr.net/npm/prosemirror-view@1.31.4/+esm", - "prosemirror-model": "https://cdn.jsdelivr.net/npm/prosemirror-model@1.19.2/+esm", + "prosemirror-model": "https://cdn.jsdelivr.net/npm/prosemirror-model@1.19.3/+esm", "prosemirror-transform": "https://cdn.jsdelivr.net//npm/prosemirror-transform@1.7.3/+esm", "prosemirror-keymap": "https://cdn.jsdelivr.net/npm/prosemirror-keymap@1.2.2/+esm", "prosemirror-example-setup": "https://cdn.jsdelivr.net/npm/prosemirror-example-setup@1.2.2/+esm", @@ -334,7 +302,7 @@

Yorkie.RGASplit

]), }); }); - printLog(); + paintData(); return; } @@ -355,32 +323,35 @@

Yorkie.RGASplit

slice: { content, openStart, openEnd }, } = step; - // 02-1. Backspace: Level delete + // 01. Move: level up/down, move left/right. // TODO(hackerwins): replaceAround replaces the given range with given gap. if (stepType === 'replaceAround') { - root.tree.move(from, to, gapFrom, gapTo); + // root.tree.move(from, to, gapFrom, gapTo); continue; } - // 02-2. Enter Key: Insert Paragraph + // 02. Split: split the given range. if ( stepType === 'replace' && openStart && openEnd && structure ) { - // TODO(hackerwins): Figure out how many depth to split. - root.tree.split(from, 2); + // TODO(hackerwins): edit should support openStart and openEnd. + // root.tree.edit(from, to, docToTreeNode(node.toJSON()), [ + // openStart, + // openEnd, + // ]); continue; } - // 02-1. Delete the given range. + // 03. Edit: Delete the given range. if (!content.content.length) { root.tree.edit(from, to); continue; } - // 03-4. Edit: Insert the given content. + // 04. Edit: Replace the given range with the given content. for (const node of content.content) { root.tree.edit(from, to, docToTreeNode(node.toJSON())); } @@ -393,7 +364,7 @@

Yorkie.RGASplit

]), }); }); - printLog(); + paintData(); }, }); @@ -443,30 +414,30 @@

Yorkie.RGASplit

const newState = view.state.apply(transform); view.updateState(newState); } - printLog(); + paintData(); }); window.view = view; view.focus(); - printLog(); + paintData(); } document.getElementById('tr-log').onclick = (e) => { const index = e.target.getAttribute('data-index'); if (index) { - printTransaction(+index); + paintTransaction(+index); } }; - function printTransaction(index) { - const t = transactions[index || 0]; + function paintTransaction(index) { + const transaction = transactions[index || 0]; - if (t) { - if (t.type === 'selection') { + if (transaction) { + if (transaction.type === 'selection') { document.getElementById( 'tr-info', - ).innerHTML = `
selection\n${JSON.stringify(
-              t.selection.toJSON(),
+            ).innerHTML = `
selection: ${JSON.stringify(
+              transaction.selection.toJSON(),
               null,
               2,
             )}
`; @@ -474,32 +445,32 @@

Yorkie.RGASplit

document.getElementById( 'tr-info', ).innerHTML = `
selection: ${JSON.stringify(
-              t.transaction.curSelection.toJSON(),
+              transaction.transaction.curSelection.toJSON(),
+              null,
+              2,
+            )},\nsteps: ${JSON.stringify(
+              transaction.transaction.steps,
               null,
               2,
-            )}, steps: ${JSON.stringify(t.transaction.steps, null, 2)}
+            )}
           
`; } } } - function printLog() { - // how to show transaction view + function paintData() { document.getElementById('tr-log').innerHTML = transactions .slice(0, 100) .map((transaction, index) => { - if (transaction.type === 'selection') { - return `.`; - } - - return `T`; + return transaction.type === 'selection' + ? '' + : `T`; }) .join(''); - printTransaction(); - printDoc(doc.getRoot().tree.tree.getRoot(), 'yorkie-log'); - printDoc(view.state.doc, 'pm-log'); - printDocList(doc.getRoot().tree.tree, 'yorkie-list-log'); + paintTree(view.state.doc, 'pm-log'); + paintTree(doc.getRoot().tree.tree.getRoot(), 'yorkie-log'); + paintTransaction(); } function buildNodes(node, depth, nodes, index) { @@ -526,57 +497,7 @@

Yorkie.RGASplit

} } - function printDocList(doc, id) { - const head = doc.dummyHead; - - const arr = []; - let node = head; - while (node) { - const nodeType = node.type; - const pos = `${node.pos.createdAt.toTestString()}-${node.pos.offset}`; - if (nodeType === 'text') { - arr.push({ - type: nodeType, - value: node.value, - pos, - removedAt: node.removedAt, - }); - } else { - arr.push({ - type: nodeType, - size: node.size, - pos, - removedAt: node.removedAt, - }); - } - - node = node.next; - } - - const html = arr - .map((node) => { - const className = node.removedAt ? 'removed' : ''; - - if (node.type === 'text') { - return `
${ - node.value === ' ' ? '  ' : node.value - }
`; - } - return `
${ - node.type - }${ - node.size ? `(${node.size})` : '' - }
`; - }) - .join(''); - - document.getElementById(id).innerHTML = html; - } - - /** - * `printDoc` prints the content of the yorkie.Text. - */ - function printDoc(doc, id) { + function paintTree(doc, id) { const nodes = []; buildNodes(doc, 0, nodes); diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index 152799df1..41230f3e9 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -40,6 +40,9 @@ import type { import { Indexable } from '@yorkie-js-sdk/src/document/document'; import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; +/** + * `TreeNode` represents a node in the tree. + */ export type TreeNode = TextNode | ElementNode; /** @@ -112,6 +115,39 @@ export class CRDTTreePos { return new CRDTTreePos(parentID, leftSiblingID); } + /** + * `fromTreePos` creates a new instance of CRDTTreePos from the given TreePos. + */ + public static fromTreePos(pos: TreePos): CRDTTreePos { + const { offset } = pos; + let { node } = pos; + let leftSibling; + + if (node.isText) { + if (node.parent!.children[0] === node && offset === 0) { + leftSibling = node.parent!; + } else { + leftSibling = node; + } + + node = node.parent!; + } else { + if (offset === 0) { + leftSibling = node; + } else { + leftSibling = node.children[offset - 1]; + } + } + + return CRDTTreePos.of( + node.id, + CRDTTreeNodeID.of( + leftSibling.getCreatedAt(), + leftSibling.getOffset() + offset, + ), + ); + } + /** * `getParentID` returns the parent ID. */ @@ -151,6 +187,29 @@ export class CRDTTreePos { }; } + /** + * `toTreeNodes` converts the pos to parent and left sibling nodes. + */ + public toTreeNodes(tree: CRDTTree): [CRDTTreeNode, CRDTTreeNode] { + const parentID = this.getParentID(); + const leftSiblingID = this.getLeftSiblingID(); + const parentNode = tree.findFloorNode(parentID); + let leftNode = tree.findFloorNode(leftSiblingID); + if (!parentNode || !leftNode) { + throw new Error(`cannot find node at ${this}`); + } + + if ( + leftSiblingID.getOffset() > 0 && + leftSiblingID.getOffset() === leftNode.id.getOffset() && + leftNode.insPrevID + ) { + leftNode = tree.findFloorNode(leftNode.insPrevID) || leftNode; + } + + return [parentNode, leftNode!]; + } + /** * `getLeftSiblingID` returns the left sibling ID. */ @@ -551,9 +610,8 @@ export class CRDTTree extends CRDTGCElement { /** * `findFloorNode` finds node of given id. */ - private findFloorNode(id: CRDTTreeNodeID) { + public findFloorNode(id: CRDTTreeNodeID): CRDTTreeNode | undefined { const entry = this.nodeMapByID.floorEntry(id); - if (!entry || !entry.key.getCreatedAt().equals(id.getCreatedAt())) { return; } @@ -562,66 +620,58 @@ export class CRDTTree extends CRDTGCElement { } /** - * `findNodesAndSplitText` finds `TreePos` of the given `CRDTTreeNodeID` and - * splits the text node if necessary. + * `findNodesAndSplit` finds `TreePos` of the given `CRDTTreeNodeID` and + * splits nodes for the given split level. * - * `CRDTTreeNodeID` is a position in the CRDT perspective. This is - * different from `TreePos` which is a position of the tree in the local - * perspective. + * The ids of the given `pos` are the ids of the node in the CRDT perspective. + * This is different from `TreePos` which is a position of the tree in the + * physical perspective. */ - public findNodesAndSplitText( + public findNodesAndSplit( pos: CRDTTreePos, editedAt: TimeTicket, ): [CRDTTreeNode, CRDTTreeNode] { - const treeNodes = this.toTreeNodes(pos); - - if (!treeNodes) { - throw new Error(`cannot find node at ${pos}`); - } - const [parentNode] = treeNodes; - let [, leftSiblingNode] = treeNodes; - - // Find the appropriate position. This logic is similar to the logical to - // handle the same position insertion of RGA. - - if (leftSiblingNode.isText) { - const absOffset = leftSiblingNode.id.getOffset(); - const split = leftSiblingNode.split( + // 01. Find the parent and left sibling node of the given position. + const [parent, leftSibling] = pos.toTreeNodes(this); + let leftNode = leftSibling; + + // 02. Split nodes for the given split level. + if (leftNode.isText) { + const absOffset = leftNode.id.getOffset(); + const split = leftNode.split( pos.getLeftSiblingID().getOffset() - absOffset, absOffset, ); if (split) { - split.insPrevID = leftSiblingNode.id; - this.nodeMapByID.put(split.id, split); - - if (leftSiblingNode.insNextID) { - const insNext = this.findFloorNode(leftSiblingNode.insNextID)!; - + split.insPrevID = leftNode.id; + if (leftNode.insNextID) { + const insNext = this.findFloorNode(leftNode.insNextID)!; insNext.insPrevID = split.id; - split.insNextID = leftSiblingNode.insNextID; + split.insNextID = leftNode.insNextID; } - leftSiblingNode.insNextID = split.id; + leftNode.insNextID = split.id; + + this.nodeMapByID.put(split.id, split); } } - const allChildren = parentNode.allChildren; - const index = - parentNode === leftSiblingNode - ? 0 - : allChildren.indexOf(leftSiblingNode) + 1; + // 03. Find the appropriate left node. If some nodes are inserted at the + // same position concurrently, then we need to find the appropriate left + // node. This is similar to RGA. + const allChildren = parent.allChildren; + const index = parent === leftNode ? 0 : allChildren.indexOf(leftNode) + 1; - for (let i = index; i < parentNode.allChildren.length; i++) { + for (let i = index; i < parent.allChildren.length; i++) { const next = allChildren[i]; - - if (next.id.getCreatedAt().after(editedAt)) { - leftSiblingNode = next; - } else { + if (!next.id.getCreatedAt().after(editedAt)) { break; } + + leftNode = next; } - return [parentNode, leftSiblingNode]; + return [parent, leftNode]; } /** @@ -632,13 +682,9 @@ export class CRDTTree extends CRDTGCElement { attributes: { [key: string]: string } | undefined, editedAt: TimeTicket, ) { - const [fromParent, fromLeft] = this.findNodesAndSplitText( - range[0], - editedAt, - ); - const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); + const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], editedAt); + const [toParent, toLeft] = this.findNodesAndSplit(range[1], editedAt); const changes: Array = []; - changes.push({ type: TreeChangeType.Style, from: this.toIndex(fromParent, fromLeft), @@ -675,11 +721,8 @@ export class CRDTTree extends CRDTGCElement { latestCreatedAtMapByActor?: Map, ): [Array, Map] { // 01. split text nodes at the given range if needed. - const [fromParent, fromLeft] = this.findNodesAndSplitText( - range[0], - editedAt, - ); - const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); + const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], editedAt); + const [toParent, toLeft] = this.findNodesAndSplit(range[1], editedAt); // TODO(hackerwins): If concurrent deletion happens, we need to seperate the // range(from, to) into multiple ranges. @@ -795,24 +838,11 @@ export class CRDTTree extends CRDTGCElement { return [changes, latestCreatedAtMap]; } - private traverseInPosRange( - fromParent: CRDTTreeNode, - fromLeft: CRDTTreeNode, - toParent: CRDTTreeNode, - toLeft: CRDTTreeNode, - callback: (node: CRDTTreeNode, contain: TagContained) => void, - ): void { - const fromIdx = this.toIndex(fromParent, fromLeft); - const toIdx = this.toIndex(toParent, toLeft); - - return this.indexTree.nodesBetween(fromIdx, toIdx, callback); - } - /** - * `editByIndex` edits the given range with the given value. + * `editT` edits the given range with the given value. * This method uses indexes instead of a pair of TreePos for testing. */ - public editByIndex( + public editT( range: [number, number], contents: Array | undefined, editedAt: TimeTicket, @@ -822,15 +852,6 @@ export class CRDTTree extends CRDTGCElement { this.edit([fromPos, toPos], contents, editedAt); } - /** - * `split` splits the node at the given index. - */ - public split(index: number, depth = 1): TreePos { - // TODO(hackerwins, easylogic): Implement this with keeping references in the list. - // return this.treeByIndex.split(index, depth); - throw new Error(`not implemented, ${index} ${depth}`); - } - /** * `move` move the given source range to the given target range. */ @@ -850,7 +871,6 @@ export class CRDTTree extends CRDTGCElement { const nodesToBeRemoved = new Set(); let count = 0; - for (const [, node] of this.removedNodeMap) { if (node.removedAt && ticket.compare(node.removedAt!) >= 0) { nodesToBeRemoved.add(node); @@ -858,12 +878,12 @@ export class CRDTTree extends CRDTGCElement { } } - [...nodesToBeRemoved].forEach((node) => { + for (const node of nodesToBeRemoved) { node.parent?.removeChild(node); this.nodeMapByID.remove(node.id); this.purge(node); this.removedNodeMap.delete(node.id.toIDString()); - }); + } return count; } @@ -894,34 +914,7 @@ export class CRDTTree extends CRDTGCElement { */ public findPos(index: number, preferText = true): CRDTTreePos { const treePos = this.indexTree.findTreePos(index, preferText); - - const { offset } = treePos; - let { node } = treePos; - let leftSibling; - - if (node.isText) { - if (node.parent!.children[0] === node && offset === 0) { - leftSibling = node.parent!; - } else { - leftSibling = node; - } - - node = node.parent!; - } else { - if (offset === 0) { - leftSibling = node; - } else { - leftSibling = node.children[offset - 1]; - } - } - - return CRDTTreePos.of( - node.id, - CRDTTreeNodeID.of( - leftSibling.getCreatedAt(), - leftSibling.getOffset() + offset, - ), - ); + return CRDTTreePos.fromTreePos(treePos); } /** @@ -936,23 +929,14 @@ export class CRDTTree extends CRDTGCElement { */ public pathToPosRange(path: Array): [CRDTTreePos, CRDTTreePos] { const fromIdx = this.pathToIndex(path); - return [this.findPos(fromIdx), this.findPos(fromIdx + 1)]; } - /** - * `pathToTreePos` finds the tree position path. - */ - public pathToTreePos(path: Array): TreePos { - return this.indexTree.pathToTreePos(path); - } - /** * `pathToPos` finds the position of the given index in the tree by path. */ public pathToPos(path: Array): CRDTTreePos { const index = this.indexTree.pathToIndex(path); - return this.findPos(index); } @@ -1028,8 +1012,7 @@ export class CRDTTree extends CRDTGCElement { */ public deepcopy(): CRDTTree { const root = this.getRoot(); - const tree = new CRDTTree(root.deepcopy(), this.getCreatedAt()); - return tree; + return new CRDTTree(root.deepcopy(), this.getCreatedAt()); } /** @@ -1040,7 +1023,6 @@ export class CRDTTree extends CRDTGCElement { leftSiblingNode: CRDTTreeNode, ): Array { const treePos = this.toTreePos(parentNode, leftSiblingNode); - if (!treePos) { return []; } @@ -1056,7 +1038,6 @@ export class CRDTTree extends CRDTGCElement { leftSiblingNode: CRDTTreeNode, ): number { const treePos = this.toTreePos(parentNode, leftSiblingNode); - if (!treePos) { return -1; } @@ -1064,84 +1045,6 @@ export class CRDTTree extends CRDTGCElement { return this.indexTree.indexOf(treePos); } - private toTreeNodes(pos: CRDTTreePos) { - const parentID = pos.getParentID(); - const leftSiblingID = pos.getLeftSiblingID(); - const parentNode = this.findFloorNode(parentID); - let leftSiblingNode = this.findFloorNode(leftSiblingID); - - if (!parentNode || !leftSiblingNode) { - return []; - } - - if ( - leftSiblingID.getOffset() > 0 && - leftSiblingID.getOffset() === leftSiblingNode.id.getOffset() && - leftSiblingNode.insPrevID - ) { - leftSiblingNode = - this.findFloorNode(leftSiblingNode.insPrevID) || leftSiblingNode; - } - - return [parentNode, leftSiblingNode!]; - } - - /** - * `toTreePos` converts the given CRDTTreePos to local TreePos. - */ - private toTreePos( - parentNode: CRDTTreeNode, - leftSiblingNode: CRDTTreeNode, - ): TreePos | undefined { - if (!parentNode || !leftSiblingNode) { - return; - } - - let treePos; - - if (parentNode.isRemoved) { - let childNode: CRDTTreeNode; - while (parentNode.isRemoved) { - childNode = parentNode; - parentNode = childNode.parent!; - } - - const childOffset = parentNode.findOffset(childNode!); - - treePos = { - node: parentNode, - offset: childOffset, - }; - } else { - if (parentNode === leftSiblingNode) { - treePos = { - node: parentNode, - offset: 0, - }; - } else { - let offset = parentNode.findOffset(leftSiblingNode); - - if (!leftSiblingNode.isRemoved) { - if (leftSiblingNode.isText) { - return { - node: leftSiblingNode, - offset: leftSiblingNode.paddedSize, - }; - } else { - offset++; - } - } - - treePos = { - node: parentNode, - offset, - }; - } - } - - return treePos; - } - /** * `indexToPath` converts the given tree index to path. */ @@ -1189,12 +1092,8 @@ export class CRDTTree extends CRDTGCElement { range: TreePosRange, timeTicket: TimeTicket, ): [Array, Array] { - const [fromParent, fromLeft] = this.findNodesAndSplitText( - range[0], - timeTicket, - ); - const [toParent, toLeft] = this.findNodesAndSplitText(range[1], timeTicket); - + const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], timeTicket); + const [toParent, toLeft] = this.findNodesAndSplit(range[1], timeTicket); return [this.toPath(fromParent, fromLeft), this.toPath(toParent, toLeft)]; } @@ -1205,12 +1104,73 @@ export class CRDTTree extends CRDTGCElement { range: TreePosRange, timeTicket: TimeTicket, ): [number, number] { - const [fromParent, fromLeft] = this.findNodesAndSplitText( - range[0], - timeTicket, - ); - const [toParent, toLeft] = this.findNodesAndSplitText(range[1], timeTicket); - + const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], timeTicket); + const [toParent, toLeft] = this.findNodesAndSplit(range[1], timeTicket); return [this.toIndex(fromParent, fromLeft), this.toIndex(toParent, toLeft)]; } + + /** + * `traverseInPosRange` traverses the tree in the given position range. + */ + private traverseInPosRange( + fromParent: CRDTTreeNode, + fromLeft: CRDTTreeNode, + toParent: CRDTTreeNode, + toLeft: CRDTTreeNode, + callback: (node: CRDTTreeNode, contain: TagContained) => void, + ): void { + const fromIdx = this.toIndex(fromParent, fromLeft); + const toIdx = this.toIndex(toParent, toLeft); + return this.indexTree.nodesBetween(fromIdx, toIdx, callback); + } + + /** + * `toTreePos` converts the given nodes to the position of the IndexTree. + */ + private toTreePos( + parentNode: CRDTTreeNode, + leftSiblingNode: CRDTTreeNode, + ): TreePos | undefined { + if (!parentNode || !leftSiblingNode) { + return; + } + + if (parentNode.isRemoved) { + let childNode: CRDTTreeNode; + while (parentNode.isRemoved) { + childNode = parentNode; + parentNode = childNode.parent!; + } + + const offset = parentNode.findOffset(childNode!); + return { + node: parentNode, + offset, + }; + } + + if (parentNode === leftSiblingNode) { + return { + node: parentNode, + offset: 0, + }; + } + + let offset = parentNode.findOffset(leftSiblingNode); + if (!leftSiblingNode.isRemoved) { + if (leftSiblingNode.isText) { + return { + node: leftSiblingNode, + offset: leftSiblingNode.paddedSize, + }; + } + + offset++; + } + + return { + node: parentNode, + offset, + }; + } } diff --git a/src/document/json/tree.ts b/src/document/json/tree.ts index b145d3d75..22c4bc022 100644 --- a/src/document/json/tree.ts +++ b/src/document/json/tree.ts @@ -153,38 +153,37 @@ function createCRDTTreeNode(context: ChangeContext, content: TreeNode) { function validateTextNode(textNode: TextNode): boolean { if (!textNode.value.length) { throw new Error('text node cannot have empty value'); - } else { - return true; } + + return true; } /** * `validateTreeNodes` ensures that treeNodes consists of only one type. */ function validateTreeNodes(treeNodes: Array): boolean { - if (treeNodes.length) { - const firstTreeNodeType = treeNodes[0].type; - if (firstTreeNodeType === DefaultTextType) { - for (const treeNode of treeNodes) { - const { type } = treeNode; - if (type !== DefaultTextType) { - throw new Error( - 'element node and text node cannot be passed together', - ); - } - validateTextNode(treeNode as TextNode); + if (!treeNodes.length) { + return true; + } + + const firstTreeNodeType = treeNodes[0].type; + if (firstTreeNodeType === DefaultTextType) { + for (const treeNode of treeNodes) { + const { type } = treeNode; + if (type !== DefaultTextType) { + throw new Error('element node and text node cannot be passed together'); } - } else { - for (const treeNode of treeNodes) { - const { type } = treeNode; - if (type === DefaultTextType) { - throw new Error( - 'element node and text node cannot be passed together', - ); - } + validateTextNode(treeNode as TextNode); + } + } else { + for (const treeNode of treeNodes) { + const { type } = treeNode; + if (type === DefaultTextType) { + throw new Error('element node and text node cannot be passed together'); } } } + return true; } @@ -363,6 +362,7 @@ export class Tree { .filter((a) => a) as Array; } + // TODO(hackerwins): Implement splitLevels. const [, maxCreatedAtMapByActor] = this.tree!.edit( [fromPos, toPos], crdtNodes.length @@ -434,18 +434,6 @@ export class Tree { return this.editInternal(fromPos, toPos, contents); } - /** - * `split` splits this tree at the given index. - */ - public split(index: number, depth: number): boolean { - if (!this.context || !this.tree) { - throw new Error('it is not initialized yet'); - } - - this.tree.split(index, depth); - return true; - } - /** * `toXML` returns the XML string of this tree. */ diff --git a/src/document/operation/tree_edit_operation.ts b/src/document/operation/tree_edit_operation.ts index 086faa955..952869457 100644 --- a/src/document/operation/tree_edit_operation.ts +++ b/src/document/operation/tree_edit_operation.ts @@ -85,6 +85,7 @@ export class TreeEditOperation extends Operation { logger.fatal(`fail to execute, only Tree can execute edit`); } const tree = parentObject as CRDTTree; + // TODO(hackerwins): Implement splitLevels. const [changes] = tree.edit( [this.fromPos, this.toPos], this.contents?.map((content) => content.deepcopy()), diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index caa2119be..e34db0f50 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -263,12 +263,12 @@ describe('Tree', () => { ); }); - const actualOperations: Array = []; + const actualOps: Array = []; doc.subscribe('$.t', (event) => { if (event.type === 'local-change') { const { operations } = event.value; - actualOperations.push( + actualOps.push( ...(operations.filter( (op) => op.type === 'tree-edit', ) as Array), @@ -289,7 +289,7 @@ describe('Tree', () => { }); assert.deepEqual( - actualOperations.map((it) => { + actualOps.map((it) => { return { type: it.type, fromPath: it.fromPath, diff --git a/test/unit/document/crdt/tree_test.ts b/test/unit/document/crdt/tree_test.ts index 3b506b9e4..b52bc4215 100644 --- a/test/unit/document/crdt/tree_test.ts +++ b/test/unit/document/crdt/tree_test.ts @@ -30,12 +30,13 @@ import { CRDTTreeNodeID, CRDTTreePos, toXML, + TreeNodeForTest, } from '@yorkie-js-sdk/src/document/crdt/tree'; /** - * `DTP` is a dummy CRDTTreeNodeID for testing. + * `idT` is a dummy CRDTTreeNodeID for testing. */ -const DTP = CRDTTreeNodeID.of(ITT, 0); +const idT = CRDTTreeNodeID.of(ITT, 0); /** * `dummyContext` is a helper context that is used for testing. @@ -47,23 +48,23 @@ const dummyContext = ChangeContext.create( ); /** - * `issuePos` is a helper function that issues a new CRDTTreeNodeID. + * `posT` is a helper function that issues a new CRDTTreeNodeID. */ -function issuePos(offset = 0): CRDTTreeNodeID { +function posT(offset = 0): CRDTTreeNodeID { return CRDTTreeNodeID.of(dummyContext.issueTimeTicket(), offset); } /** - * `issueTime` is a helper function that issues a new TimeTicket. + * `timeT` is a helper function that issues a new TimeTicket. */ -function issueTime(): TimeTicket { +function timeT(): TimeTicket { return dummyContext.issueTimeTicket(); } describe('CRDTTreeNode', function () { it('Can be created', function () { - const node = new CRDTTreeNode(DTP, 'text', 'hello'); - assert.equal(node.id, DTP); + const node = new CRDTTreeNode(idT, 'text', 'hello'); + assert.equal(node.id, idT); assert.equal(node.type, 'text'); assert.equal(node.value, 'hello'); assert.equal(node.size, 5); @@ -72,8 +73,8 @@ describe('CRDTTreeNode', function () { }); it('Can be split', function () { - const para = new CRDTTreeNode(DTP, 'p', []); - para.append(new CRDTTreeNode(DTP, 'text', 'helloyorkie')); + const para = new CRDTTreeNode(idT, 'p', []); + para.append(new CRDTTreeNode(idT, 'text', 'helloyorkie')); assert.equal(toXML(para), /*html*/ `

helloyorkie

`); assert.equal(para.size, 11); assert.equal(para.isText, false); @@ -95,101 +96,75 @@ describe('CRDTTree.Edit', function () { it('Can inserts nodes with edit', function () { // 0 // - const tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'r'), issueTime()); - assert.equal(tree.getRoot().size, 0); - assert.equal(tree.toXML(), /*html*/ ``); + const t = new CRDTTree(new CRDTTreeNode(posT(), 'r'), timeT()); + assert.equal(t.getRoot().size, 0); + assert.equal(t.toXML(), /*html*/ ``); // 1 //

- tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - assert.equal(tree.toXML(), /*html*/ `

`); - assert.equal(tree.getRoot().size, 2); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + assert.equal(t.toXML(), /*html*/ `

`); + assert.equal(t.getRoot().size, 2); // 1 //

h e l l o

- tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'hello')], - issueTime(), - ); - assert.equal(tree.toXML(), /*html*/ `

hello

`); - assert.equal(tree.getRoot().size, 7); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'hello')], timeT()); + assert.equal(t.toXML(), /*html*/ `

hello

`); + assert.equal(t.getRoot().size, 7); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 //

h e l l o

w o r l d

- const p = new CRDTTreeNode(issuePos(), 'p', []); - p.insertAt(new CRDTTreeNode(issuePos(), 'text', 'world'), 0); - tree.editByIndex([7, 7], [p], issueTime()); - assert.equal(tree.toXML(), /*html*/ `

hello

world

`); - assert.equal(tree.getRoot().size, 14); + const p = new CRDTTreeNode(posT(), 'p', []); + p.insertAt(new CRDTTreeNode(posT(), 'text', 'world'), 0); + t.editT([7, 7], [p], timeT()); + assert.equal(t.toXML(), /*html*/ `

hello

world

`); + assert.equal(t.getRoot().size, 14); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //

h e l l o !

w o r l d

- tree.editByIndex( - [6, 6], - [new CRDTTreeNode(issuePos(), 'text', '!')], - issueTime(), - ); - assert.equal(tree.toXML(), /*html*/ `

hello!

world

`); - - assert.deepEqual( - JSON.stringify(tree.toTestTreeNode()), - JSON.stringify({ - type: 'r', - children: [ - { - type: 'p', - children: [ - { type: 'text', value: 'hello', size: 5, isRemoved: false }, - { type: 'text', value: '!', size: 1, isRemoved: false }, - ], - size: 6, - isRemoved: false, - }, - { - type: 'p', - children: [ - { type: 'text', value: 'world', size: 5, isRemoved: false }, - ], - size: 5, - isRemoved: false, - }, - ], - size: 15, - isRemoved: false, - }), - ); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '!')], timeT()); + assert.equal(t.toXML(), /*html*/ `

hello!

world

`); + + assert.deepEqual(t.toTestTreeNode(), { + type: 'r', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'hello', size: 5, isRemoved: false }, + { type: 'text', value: '!', size: 1, isRemoved: false }, + ], + size: 6, + isRemoved: false, + } as TreeNodeForTest, + { + type: 'p', + children: [ + { type: 'text', value: 'world', size: 5, isRemoved: false }, + ], + size: 5, + isRemoved: false, + } as TreeNodeForTest, + ], + size: 15, + isRemoved: false, + }); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //

h e l l o ~ !

w o r l d

- tree.editByIndex( - [6, 6], - [new CRDTTreeNode(issuePos(), 'text', '~')], - issueTime(), - ); - assert.equal(tree.toXML(), /*html*/ `

hello~!

world

`); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '~')], timeT()); + assert.equal(t.toXML(), /*html*/ `

hello~!

world

`); }); it('Can delete text nodes with edit', function () { // 01. Create a tree with 2 paragraphs. // 0 1 2 3 4 5 6 7 8 //

a b

c d

- const tree = new CRDTTree( - new CRDTTreeNode(issuePos(), 'root'), - issueTime(), - ); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - tree.editByIndex([4, 4], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [5, 5], - [new CRDTTreeNode(issuePos(), 'text', 'cd')], - issueTime(), - ); + const tree = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + tree.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + tree.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + tree.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], timeT()); + tree.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); assert.deepEqual(tree.toXML(), /*html*/ `

ab

cd

`); let treeNode = tree.toTestTreeNode(); @@ -200,7 +175,7 @@ describe('CRDTTree.Edit', function () { // 02. delete b from first paragraph // 0 1 2 3 4 5 6 7 //

a

c d

- tree.editByIndex([2, 3], undefined, issueTime()); + tree.editT([2, 3], undefined, timeT()); assert.deepEqual(tree.toXML(), /*html*/ `

a

cd

`); treeNode = tree.toTestTreeNode(); @@ -210,210 +185,185 @@ describe('CRDTTree.Edit', function () { }); it('Can find the closest TreePos when parentNode or leftSiblingNode does not exist', function () { - const tree = new CRDTTree( - new CRDTTreeNode(issuePos(), 'root'), - issueTime(), - ); + const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - const pNode = new CRDTTreeNode(issuePos(), 'p'); - const textNode = new CRDTTreeNode(issuePos(), 'text', 'ab'); + const pNode = new CRDTTreeNode(posT(), 'p'); + const textNode = new CRDTTreeNode(posT(), 'text', 'ab'); // 0 1 2 3 4 //

a b

- tree.editByIndex([0, 0], [pNode], issueTime()); - tree.editByIndex([1, 1], [textNode], issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); + t.editT([0, 0], [pNode], timeT()); + t.editT([1, 1], [textNode], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // Find the closest index.TreePos when leftSiblingNode in crdt.TreePos is removed. // 0 1 2 //

- tree.editByIndex([1, 3], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

`); + t.editT([1, 3], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

`); - let [parent, left] = tree.findNodesAndSplitText( + let [parent, left] = t.findNodesAndSplit( new CRDTTreePos(pNode.id, textNode.id), - issueTime(), + timeT(), ); - assert.equal(tree.toIndex(parent, left), 1); + assert.equal(t.toIndex(parent, left), 1); // Find the closest index.TreePos when parentNode in crdt.TreePos is removed. // 0 // - tree.editByIndex([0, 2], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ ``); + t.editT([0, 2], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ ``); - [parent, left] = tree.findNodesAndSplitText( + [parent, left] = t.findNodesAndSplit( new CRDTTreePos(pNode.id, textNode.id), - issueTime(), + timeT(), ); - assert.equal(tree.toIndex(parent, left), 0); + assert.equal(t.toIndex(parent, left), 0); }); }); -describe.skip('CRDTTree.Split', function () { +describe('CRDTTree.Split', function () { it('Can split text nodes', function () { // 00. Create a tree with 2 paragraphs. // 0 1 6 11 //

hello world

- const tree = new CRDTTree( - new CRDTTreeNode(issuePos(), 'root'), - issueTime(), - ); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'helloworld')], - issueTime(), - ); + const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'helloworld')], timeT()); + const expectedIntial = { + type: 'root', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'helloworld', size: 10, isRemoved: false }, + ], + size: 10, + isRemoved: false, + } as TreeNodeForTest, + ], + size: 12, + isRemoved: false, + }; + assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 01. Split left side of 'helloworld'. - tree.split(1, 1); - // TODO(JOOHOJANG): make new helper function when implement Tree.split - //betweenEqual(tree, 1, 11, ['text.helloworld']); + t.editT([1, 1], undefined, timeT()); + assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 02. Split right side of 'helloworld'. - tree.split(11, 1); - // TODO(JOOHOJANG): make new helper function when implement Tree.split - //betweenEqual(tree, 1, 11, ['text.helloworld']); + t.editT([11, 11], undefined, timeT()); + assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 03. Split 'helloworld' into 'hello' and 'world'. - tree.split(6, 1); - // TODO(JOOHOJANG): make new helper function when implement Tree.split - //betweenEqual(tree, 1, 11, ['text.hello', 'text.world']); + t.editT([6, 6], undefined, timeT()); + assert.deepEqual(t.toTestTreeNode(), { + type: 'root', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'hello', size: 5, isRemoved: false }, + { type: 'text', value: 'world', size: 5, isRemoved: false }, + ], + size: 10, + isRemoved: false, + } as TreeNodeForTest, + ], + size: 12, + isRemoved: false, + }); }); - it('Can split element nodes', function () { + it.skip('Can split element nodes level 1', function () { + // 0 1 2 3 4 + //

a b

+ // 01. Split position 1. - let tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - tree.split(1, 2); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - assert.equal(tree.getSize(), 6); + let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + // t.editT([1, 1], undefined, [1, 1], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + assert.equal(t.getSize(), 6); // 02. Split position 2. - // 0 1 2 3 4 - //

a b

- tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - tree.split(2, 2); - assert.deepEqual(tree.toXML(), /*html*/ `

a

b

`); - assert.equal(tree.getSize(), 6); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + // t.editT([2, 2], undefined, [1, 1], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

a

b

`); + assert.equal(t.getSize(), 6); // 03. Split position 3. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - tree.split(3, 2); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - assert.equal(tree.getSize(), 6); - - // 04. Split position 3. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'cd')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

abcd

`); - tree.split(3, 2); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

cd

`); - assert.equal(tree.getSize(), 8); - - // 05. Split multiple nodes level 1. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex( - [2, 2], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - tree.split(3, 1); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - assert.equal(tree.getSize(), 6); - - // Split multiple nodes level 2. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex( - [2, 2], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - tree.split(3, 2); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + // t.editT([3, 3], undefined, [1, 1], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + assert.equal(t.getSize(), 6); + }); + + it.skip('Can split element nodes multi-level', function () { + // 0 1 2 3 4 5 6 + //

a b

+ + // 01. Split nodes level 1. + let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + // t.editT([3, 3], undefined, [1, 1], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - assert.equal(tree.getSize(), 8); - - // Split multiple nodes level 3. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex( - [2, 2], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), + + // 02. Split nodes level 2. + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + // t.editT([3, 3], undefined, [2, 2], timeT()); + assert.deepEqual( + t.toXML(), + /*html*/ `

a

b

`, ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); - tree.split(3, 3); + + // Split multiple nodes level 3. But, it is allowed to split only level 2. + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); + // t.editT([3, 3], undefined, [3, 3], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

a

b

`, ); - assert.equal(tree.getSize(), 10); }); - it('Can split and merge element nodes by edit', function () { - const tree = new CRDTTree( - new CRDTTreeNode(issuePos(), 'root'), - issueTime(), - ); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'abcd')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

abcd

`); - assert.equal(tree.getSize(), 6); + it.skip('Can split and merge element nodes by edit', function () { + const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'abcd')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

abcd

`); + assert.equal(t.getSize(), 6); // 0 1 2 3 4 5 6 7 8 //

a b

c d

- tree.split(3, 2); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

cd

`); - assert.equal(tree.getSize(), 8); + // tree.split(3, 2); + assert.deepEqual(t.toXML(), /*html*/ `

ab

cd

`); + assert.equal(t.getSize(), 8); - tree.editByIndex([3, 5], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

abcd

`); - assert.equal(tree.getSize(), 6); + t.editT([3, 5], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

abcd

`); + assert.equal(t.getSize(), 6); }); }); @@ -422,215 +372,150 @@ describe('CRDTTree.Merge', function () { // 01. Create a tree with 2 paragraphs. // 0 1 2 3 4 5 6 7 8 //

a b

c d

- const tree = new CRDTTree( - new CRDTTreeNode(issuePos(), 'root'), - issueTime(), - ); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - tree.editByIndex([4, 4], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [5, 5], - [new CRDTTreeNode(issuePos(), 'text', 'cd')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

cd

`); + const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

cd

`); // 02. delete b, c and the second paragraph. // 0 1 2 3 4 //

a d

- tree.editByIndex([2, 6], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

ad

`); + t.editT([2, 6], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ad

`); - const node = tree.toTestTreeNode(); + const node = t.toTestTreeNode(); assert.equal(node.size, 4); // root assert.equal(node.children![0].size, 2); // p assert.equal(node.children![0].children![0].size, 1); // a assert.equal(node.children![0].children![1].size, 1); // d // 03. insert a new text node at the start of the first paragraph. - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', '@')], - issueTime(), - ); - assert.deepEqual(tree.toXML(), /*html*/ `

@ad

`); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', '@')], timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

@ad

`); }); it('Can delete nodes between elements in different level with edit', function () { // 01. Create a tree with 2 paragraphs. // 0 1 2 3 4 5 6 7 8 9 10 //

a b

c d

- const tree = new CRDTTree( - new CRDTTreeNode(issuePos(), 'root'), - issueTime(), - ); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex( - [2, 2], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - tree.editByIndex([6, 6], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [7, 7], - [new CRDTTreeNode(issuePos(), 'text', 'cd')], - issueTime(), - ); + const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([7, 7], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

cd

`, ); // 02. delete b, c and second paragraph. // 0 1 2 3 4 5 //

a d - tree.editByIndex([3, 8], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

ad

`); + t.editT([3, 8], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ad

`); }); it.skip('Can merge different levels with edit', function () { + // TODO(hackerwins): Fix this test. // 01. edit between two element nodes in the same hierarchy. // 0 1 2 3 4 5 6 7 8 //

a b

- let tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex([2, 2], [new CRDTTreeNode(issuePos(), 'i')], issueTime()); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); + let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - tree.editByIndex([5, 6], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); + t.editT([5, 6], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 02. edit between two element nodes in same hierarchy. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex([2, 2], [new CRDTTreeNode(issuePos(), 'i')], issueTime()); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - tree.editByIndex([6, 7], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); + t.editT([6, 7], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 03. edit between text and element node in same hierarchy. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex([2, 2], [new CRDTTreeNode(issuePos(), 'i')], issueTime()); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - tree.editByIndex([4, 6], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

a

`); + t.editT([4, 6], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

a

`); // 04. edit between text and element node in same hierarchy. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex([2, 2], [new CRDTTreeNode(issuePos(), 'i')], issueTime()); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - tree.editByIndex([5, 7], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

ab

`); + t.editT([5, 7], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 05. edit between text and element node in same hierarchy. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex([2, 2], [new CRDTTreeNode(issuePos(), 'i')], issueTime()); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - tree.editByIndex([4, 7], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

a

`); + t.editT([4, 7], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

a

`); // 06. edit between text and element node in same hierarchy. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([1, 1], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex([2, 2], [new CRDTTreeNode(issuePos(), 'i')], issueTime()); - tree.editByIndex( - [3, 3], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

`, ); - tree.editByIndex([3, 7], undefined, issueTime()); - assert.deepEqual(tree.toXML(), /*html*/ `

`); + t.editT([3, 7], undefined, timeT()); + assert.deepEqual(t.toXML(), /*html*/ `

`); // 07. edit between text and element node in same hierarchy. - tree = new CRDTTree(new CRDTTreeNode(issuePos(), 'root'), issueTime()); - tree.editByIndex([0, 0], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex( - [1, 1], - [new CRDTTreeNode(issuePos(), 'text', 'ab')], - issueTime(), - ); - tree.editByIndex([4, 4], [new CRDTTreeNode(issuePos(), 'p')], issueTime()); - tree.editByIndex([5, 5], [new CRDTTreeNode(issuePos(), 'b')], issueTime()); - tree.editByIndex( - [6, 6], - [new CRDTTreeNode(issuePos(), 'text', 'cd')], - issueTime(), - ); - tree.editByIndex( - [10, 10], - [new CRDTTreeNode(issuePos(), 'p')], - issueTime(), - ); - tree.editByIndex( - [11, 11], - [new CRDTTreeNode(issuePos(), 'text', 'ef')], - issueTime(), - ); + t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([5, 5], [new CRDTTreeNode(posT(), 'b')], timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); + t.editT([10, 10], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([11, 11], [new CRDTTreeNode(posT(), 'text', 'ef')], timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

cd

ef

`, ); - tree.editByIndex([9, 10], undefined, issueTime()); + t.editT([9, 10], undefined, timeT()); assert.deepEqual( - tree.toXML(), + t.toXML(), /*html*/ `

ab

cd

ef

`, ); }); From baa2797e8ffa0e5ce21466a82b3c2ca771148e81 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:21:16 +0900 Subject: [PATCH 03/48] Prevent empty ops are applied during undo/redo (#687) This commit addresses the issue of client sequences being absent on the server. It accomplishes this by preventing the update of changeID. --- src/document/document.ts | 29 +++++++------ test/integration/object_test.ts | 76 +++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/src/document/document.ts b/src/document/document.ts index 097acc8ca..0dbc4d441 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -550,6 +550,7 @@ export class Document { this.changeID = change.getID(); // 03. Publish the document change event. + // NOTE(chacha912): Check opInfos, which represent the actually executed operations. if (opInfos.length > 0) { this.publish({ type: DocEventType.LocalChange, @@ -846,6 +847,15 @@ export class Document { return this.checkpoint; } + /** + * `getChangeID` returns the change id of this document. + * + * @internal + */ + public getChangeID(): ChangeID { + return this.changeID; + } + /** * `hasLocalChanges` returns whether this document has local changes or not. * @@ -1309,18 +1319,15 @@ export class Document { this.internalHistory.pushRedo(reverseOps); } - // TODO(chacha912): When there is no applied operation or presence + // NOTE(chacha912): When there is no applied operation or presence // during undo/redo, skip propagating change remotely. - // In the database, it may appear as if the client sequence is missing. - if (change.hasPresenceChange() || opInfos.length > 0) { - this.localChanges.push(change); + if (!change.hasPresenceChange() && opInfos.length === 0) { + return; } + this.localChanges.push(change); this.changeID = change.getID(); const actorID = this.changeID.getActorID()!; - // NOTE(chacha912): Although operations are included in the change, they - // may not be executable (e.g., when the target element has been deleted). - // So we check opInfos, which represent the actually executed operations. if (opInfos.length > 0) { this.publish({ type: DocEventType.LocalChange, @@ -1400,15 +1407,13 @@ export class Document { // NOTE(chacha912): When there is no applied operation or presence // during undo/redo, skip propagating change remotely. - if (change.hasPresenceChange() || opInfos.length > 0) { - this.localChanges.push(change); + if (!change.hasPresenceChange() && opInfos.length === 0) { + return; } + this.localChanges.push(change); this.changeID = change.getID(); const actorID = this.changeID.getActorID()!; - // NOTE(chacha912): Although operations are included in the change, they - // may not be executable (e.g., when the target element has been deleted). - // So we check opInfos, which represent the actually executed operations. if (opInfos.length > 0) { this.publish({ type: DocEventType.LocalChange, diff --git a/test/integration/object_test.ts b/test/integration/object_test.ts index 666f61658..8a693795b 100644 --- a/test/integration/object_test.ts +++ b/test/integration/object_test.ts @@ -507,6 +507,82 @@ describe('Object', function () { await client1.sync(); }); + it(`Should not propagate changes when there is no applied undo operation`, async function ({ + task, + }) { + interface TestDoc { + shape?: { color: string }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + let doc1ChangeID = doc1.getChangeID(); + let doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 1); + assert.equal(doc1Checkpoint.getClientSeq(), 1); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 1); + + doc1.update((root) => { + root.shape = { color: 'black' }; + }, 'init doc'); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"black"}}'); + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 2); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"black"}}'); + + doc2.update((root) => { + delete root.shape; + }, 'delete shape'); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc2.toSortedJSON(), '{}'); + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 4); + + // c2 deleted the shape, so the reverse operation cannot be applied + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc1.getRedoStackForTest().length, 0); + assert.equal(doc1.history.canRedo(), false); + await client1.sync(); + await client2.sync(); + await client1.sync(); + // Since there are no applied operations, there should be no change in the sequence. + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 4); + + doc1.update((root) => { + root.shape = { color: 'red' }; + }); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"red"}}'); + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 3); + assert.equal(doc1Checkpoint.getClientSeq(), 3); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 5); + }); + it('Can handle concurrent undo/redo: local undo & global redo', async function ({ task, }) { From 5b1425d2eaf5605fdf6f9e29760d55275781b56e Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:42:33 +0900 Subject: [PATCH 04/48] Add missing removedAt during Primitive deepcopy (#692) When performing a Primitive deepcopy, the absence of removedAt led to a problem where deleted elements reappeared. This PR addresses the issue by making sure that removedAt is included in the primitive deepcopy. --- src/document/crdt/primitive.ts | 1 + src/document/json/object.ts | 7 ++++++- test/integration/object_test.ts | 2 +- test/unit/document/document_test.ts | 21 +++++++++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/document/crdt/primitive.ts b/src/document/crdt/primitive.ts index b3c4b440c..d0ba93c01 100644 --- a/src/document/crdt/primitive.ts +++ b/src/document/crdt/primitive.ts @@ -135,6 +135,7 @@ export class Primitive extends CRDTElement { public deepcopy(): Primitive { const primitive = Primitive.of(this.value, this.getCreatedAt()); primitive.setMovedAt(this.getMovedAt()); + primitive.setRemovedAt(this.getRemovedAt()); return primitive; } diff --git a/src/document/json/object.ts b/src/document/json/object.ts index 8755b65ee..e60cc4704 100644 --- a/src/document/json/object.ts +++ b/src/document/json/object.ts @@ -169,7 +169,12 @@ export class ObjectProxy { const primitive = Primitive.of(value as PrimitiveValue, ticket); setAndRegister(primitive); context.push( - SetOperation.create(key, primitive, target.getCreatedAt(), ticket), + SetOperation.create( + key, + primitive.deepcopy(), + target.getCreatedAt(), + ticket, + ), ); } else if (Array.isArray(value)) { const array = CRDTArray.create(ticket); diff --git a/test/integration/object_test.ts b/test/integration/object_test.ts index 8a693795b..40e9411b3 100644 --- a/test/integration/object_test.ts +++ b/test/integration/object_test.ts @@ -253,7 +253,7 @@ describe('Object', function () { assert.equal(doc.toSortedJSON(), `{}`); assert.deepEqual( doc.getRedoStackForTest().at(-1)?.map(toStringHistoryOp), - ['0:00:0.SET.shape={"color":"black"}', '1:00:1.SET.color="black"'], + ['0:00:0.SET.shape={}', '1:00:1.SET.color="black"'], ); doc.history.redo(); diff --git a/test/unit/document/document_test.ts b/test/unit/document/document_test.ts index 6a55df498..eb92746ac 100644 --- a/test/unit/document/document_test.ts +++ b/test/unit/document/document_test.ts @@ -229,6 +229,27 @@ describe.sequential('Document', function () { assert.equal(doc.toSortedJSON(), '{"list":[{"id":1}]}'); }); + it('splice array with nested object', function () { + const doc = new Document<{ + list: Array<{ point: { x?: number; y?: number } }>; + }>('test-doc'); + + doc.update((root) => { + root.list = [{ point: { x: 0, y: 0 } }, { point: { x: 1, y: 1 } }]; + delete root.list[1].point.y; + }); + assert.equal( + doc.toSortedJSON(), + '{"list":[{"point":{"x":0,"y":0}},{"point":{"x":1}}]}', + ); + + doc.update((root) => { + const res = root.list.splice(1, 1); + assert.equal(res.toString(), '{"point":{"x":1}}'); + }); + assert.equal(doc.toSortedJSON(), '{"list":[{"point":{"x":0,"y":0}}]}'); + }); + describe('should support standard array read-only operations', () => { type TestDoc = { empty: []; From ed35072c4b7e3eb19735a3a9dd8df831450cb5bb Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Thu, 23 Nov 2023 19:18:00 +0900 Subject: [PATCH 05/48] Enhance Set and Add for representing nested elements (#691) Previously, when setting values for objects or arrays, we followed a process of creating outer shells first ({}) and then individually setting inner values, resulting in multiple operations. This PR introduces a modification to streamline this process by allowing the direct setting of initial values in a single operation. This enhancement simplifies the workflow and reduces the number of generated operations. With this PR, the set operation is enhanced to handle both outer shells and inner values properly. This ensures that the set operation is generated only once, and undo operations are applied correctly. --------- Co-authored-by: Youngteac Hong --- public/whiteboard.html | 3 +- src/api/converter.ts | 37 ++- src/document/crdt/array.ts | 15 +- src/document/crdt/element.ts | 3 + src/document/crdt/object.ts | 15 +- src/document/crdt/root.ts | 82 +++---- src/document/json/array.ts | 93 +++----- src/document/json/element.ts | 46 ++++ src/document/json/object.ts | 146 ++++-------- src/document/operation/add_operation.ts | 3 +- src/document/operation/remove_operation.ts | 35 +-- src/document/operation/set_operation.ts | 30 ++- test/integration/document_test.ts | 44 +--- test/integration/gc_test.ts | 31 ++- test/integration/object_test.ts | 264 ++++++++++++++++++++- 15 files changed, 561 insertions(+), 286 deletions(-) diff --git a/public/whiteboard.html b/public/whiteboard.html index ba70d3b63..baaee3c89 100644 --- a/public/whiteboard.html +++ b/public/whiteboard.html @@ -169,8 +169,7 @@

const selectedShape = root.shapes.find( (shape) => shape.id === selectedShapeID, ); - selectedShape.point.x = movingShapePoint.x; - selectedShape.point.y = movingShapePoint.y; + selectedShape.point = movingShapePoint; presence.set({ movingShapePoint: null }); }); } diff --git a/src/api/converter.ts b/src/api/converter.ts index 7e5b07a92..b86a777ff 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -208,9 +208,11 @@ function toElementSimple(element: CRDTElement): PbJSONElementSimple { if (element instanceof CRDTObject) { pbElementSimple.setType(PbValueType.VALUE_TYPE_JSON_OBJECT); pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); + pbElementSimple.setValue(objectToBytes(element)); } else if (element instanceof CRDTArray) { pbElementSimple.setType(PbValueType.VALUE_TYPE_JSON_ARRAY); pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); + pbElementSimple.setValue(arrayToBytes(element)); } else if (element instanceof CRDTText) { pbElementSimple.setType(PbValueType.VALUE_TYPE_TEXT); pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); @@ -835,9 +837,19 @@ function fromCounterType(pbValueType: PbValueType): CounterType { function fromElementSimple(pbElementSimple: PbJSONElementSimple): CRDTElement { switch (pbElementSimple.getType()) { case PbValueType.VALUE_TYPE_JSON_OBJECT: - return CRDTObject.create(fromTimeTicket(pbElementSimple.getCreatedAt())!); + if (!pbElementSimple.getValue()) { + return CRDTObject.create( + fromTimeTicket(pbElementSimple.getCreatedAt())!, + ); + } + return bytesToObject(pbElementSimple.getValue_asU8()); case PbValueType.VALUE_TYPE_JSON_ARRAY: - return CRDTArray.create(fromTimeTicket(pbElementSimple.getCreatedAt())!); + if (!pbElementSimple.getValue()) { + return CRDTArray.create( + fromTimeTicket(pbElementSimple.getCreatedAt())!, + ); + } + return bytesToArray(pbElementSimple.getValue_asU8()); case PbValueType.VALUE_TYPE_TEXT: return CRDTText.create( RGATreeSplit.create(), @@ -1343,7 +1355,7 @@ function bytesToSnapshot

( */ function bytesToObject(bytes?: Uint8Array): CRDTObject { if (!bytes) { - return CRDTObject.create(InitialTimeTicket); + throw new Error('bytes is empty'); } const pbElement = PbJSONElement.deserializeBinary(bytes); @@ -1357,6 +1369,25 @@ function objectToBytes(obj: CRDTObject): Uint8Array { return toElement(obj).serializeBinary(); } +/** + * `bytesToArray` creates an CRDTArray from the given bytes. + */ +function bytesToArray(bytes?: Uint8Array): CRDTArray { + if (!bytes) { + throw new Error('bytes is empty'); + } + + const pbElement = PbJSONElement.deserializeBinary(bytes); + return fromArray(pbElement.getJsonArray()!); +} + +/** + * `arrayToBytes` converts the given CRDTArray to bytes. + */ +function arrayToBytes(array: CRDTArray): Uint8Array { + return toArray(array).serializeBinary(); +} + /** * `bytesToTree` creates an CRDTTree from the given bytes. */ diff --git a/src/document/crdt/array.ts b/src/document/crdt/array.ts index 9ad8513c2..8a930d4e9 100644 --- a/src/document/crdt/array.ts +++ b/src/document/crdt/array.ts @@ -39,8 +39,19 @@ export class CRDTArray extends CRDTContainer { /** * `create` creates a new instance of Array. */ - public static create(createdAt: TimeTicket): CRDTArray { - return new CRDTArray(createdAt, RGATreeList.create()); + public static create( + createdAt: TimeTicket, + value?: Array, + ): CRDTArray { + if (!value) { + return new CRDTArray(createdAt, RGATreeList.create()); + } + + const elements = RGATreeList.create(); + for (const v of value) { + elements.insertAfter(elements.getLastCreatedAt(), v.deepcopy()); + } + return new CRDTArray(createdAt, elements); } /** diff --git a/src/document/crdt/element.ts b/src/document/crdt/element.ts index 7cd93f7e8..5eca00a76 100644 --- a/src/document/crdt/element.ts +++ b/src/document/crdt/element.ts @@ -99,6 +99,9 @@ export abstract class CRDTElement { removedAt.after(this.getPositionedAt()) && (!this.removedAt || removedAt.after(this.removedAt)) ) { + // NOTE(chacha912): If it's a CRDTContainer, removedAt is marked only on + // the top-level element, without marking all descendant elements. This + // enhances the speed of deletion. this.removedAt = removedAt; return true; } diff --git a/src/document/crdt/object.ts b/src/document/crdt/object.ts index 86b650a61..a9ca13ee6 100644 --- a/src/document/crdt/object.ts +++ b/src/document/crdt/object.ts @@ -39,8 +39,19 @@ export class CRDTObject extends CRDTContainer { /** * `create` creates a new instance of CRDTObject. */ - public static create(createdAt: TimeTicket): CRDTObject { - return new CRDTObject(createdAt, ElementRHT.create()); + public static create( + createdAt: TimeTicket, + value?: { [key: string]: CRDTElement }, + ): CRDTObject { + if (!value) { + return new CRDTObject(createdAt, ElementRHT.create()); + } + + const memberNodes = ElementRHT.create(); + for (const [k, v] of Object.entries(value)) { + memberNodes.set(k, v.deepcopy(), v.getCreatedAt()); + } + return new CRDTObject(createdAt, memberNodes); } /** diff --git a/src/document/crdt/root.ts b/src/document/crdt/root.ts index 5e0c89596..beecb02f3 100644 --- a/src/document/crdt/root.ts +++ b/src/document/crdt/root.ts @@ -82,18 +82,7 @@ export class CRDTRoot { this.removedElementSetByCreatedAt = new Set(); this.elementHasRemovedNodesSetByCreatedAt = new Set(); this.opsForTest = []; - - this.elementPairMapByCreatedAt.set( - this.rootObject.getCreatedAt().toIDString(), - { element: this.rootObject }, - ); - - rootObject.getDescendants( - (elem: CRDTElement, parent: CRDTContainer): boolean => { - this.registerElement(elem, parent); - return false; - }, - ); + this.registerElement(rootObject, undefined); } /** @@ -115,6 +104,16 @@ export class CRDTRoot { return pair.element; } + /** + * `findElementPairByCreatedAt` returns the element and parent pair + * of given creation time. + */ + public findElementPairByCreatedAt( + createdAt: TimeTicket, + ): CRDTElementPair | undefined { + return this.elementPairMapByCreatedAt.get(createdAt.toIDString()); + } + /** * `createSubPaths` creates an array of the sub paths for the given element. */ @@ -150,23 +149,45 @@ export class CRDTRoot { } /** - * `registerElement` registers the given element to hash table. + * `registerElement` registers the given element and its descendants to hash table. */ - public registerElement(element: CRDTElement, parent: CRDTContainer): void { + public registerElement(element: CRDTElement, parent?: CRDTContainer): void { this.elementPairMapByCreatedAt.set(element.getCreatedAt().toIDString(), { parent, element, }); + + if (element instanceof CRDTContainer) { + element.getDescendants((elem, parent) => { + this.registerElement(elem, parent); + return false; + }); + } } /** - * `deregisterElement` deregister the given element from hash table. + * `deregisterElement` deregister the given element and its descendants from hash table. */ - public deregisterElement(element: CRDTElement): void { - this.elementPairMapByCreatedAt.delete(element.getCreatedAt().toIDString()); - this.removedElementSetByCreatedAt.delete( - element.getCreatedAt().toIDString(), - ); + public deregisterElement(element: CRDTElement): number { + let count = 0; + + const deregisterElementInternal = (elem: CRDTElement) => { + const createdAt = elem.getCreatedAt().toIDString(); + this.elementPairMapByCreatedAt.delete(createdAt); + this.removedElementSetByCreatedAt.delete(createdAt); + count++; + + if (elem instanceof CRDTContainer) { + elem.getDescendants((e) => { + deregisterElementInternal(e); + return false; + }); + } + }; + + deregisterElementInternal(element); + + return count; } /** @@ -253,7 +274,7 @@ export class CRDTRoot { ticket.compare(pair.element.getRemovedAt()!) >= 0 ) { pair.parent!.purge(pair.element); - count += this.garbageCollectInternal(pair.element); + count += this.deregisterElement(pair.element); } } @@ -273,25 +294,6 @@ export class CRDTRoot { return count; } - private garbageCollectInternal(element: CRDTElement): number { - let count = 0; - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const callback = (elem: CRDTElement, parent?: CRDTContainer): boolean => { - this.deregisterElement(elem); - count++; - return false; - }; - - callback(element); - - if (element instanceof CRDTContainer) { - element.getDescendants(callback); - } - - return count; - } - /** * `toJSON` returns the JSON encoding of this root object. */ diff --git a/src/document/json/array.ts b/src/document/json/array.ts index b8e45b1d2..7c58d347e 100644 --- a/src/document/json/array.ts +++ b/src/document/json/array.ts @@ -21,18 +21,14 @@ import { MoveOperation } from '@yorkie-js-sdk/src/document/operation/move_operat import { RemoveOperation } from '@yorkie-js-sdk/src/document/operation/remove_operation'; import { ChangeContext } from '@yorkie-js-sdk/src/document/change/context'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; -import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; -import { - Primitive, - PrimitiveValue, -} from '@yorkie-js-sdk/src/document/crdt/primitive'; -import { ObjectProxy } from '@yorkie-js-sdk/src/document/json/object'; +import { Primitive } from '@yorkie-js-sdk/src/document/crdt/primitive'; import { JSONElement, WrappedElement, toWrappedElement, toJSONElement, + buildCRDTElement, } from '@yorkie-js-sdk/src/document/json/element'; /** @@ -329,6 +325,22 @@ export class ArrayProxy { } } + /** + * `buildArrayElements` constructs array elements based on the user-provided array. + */ + public static buildArrayElements( + context: ChangeContext, + value: Array, + ): Array { + const elements: Array = []; + for (const v of value) { + const createdAt = context.issueTimeTicket(); + const elem = buildCRDTElement(context, v, createdAt); + elements.push(elem); + } + return elements; + } + /** * `pushInternal` pushes the value to the target array. */ @@ -439,58 +451,19 @@ export class ArrayProxy { prevCreatedAt: TimeTicket, value: unknown, ): CRDTElement { - const ticket = context.issueTimeTicket(); - if (Primitive.isSupport(value)) { - const primitive = Primitive.of(value as PrimitiveValue, ticket); - const clone = primitive.deepcopy(); - target.insertAfter(prevCreatedAt, clone); - context.registerElement(clone, target); - context.push( - AddOperation.create( - target.getCreatedAt(), - prevCreatedAt, - primitive.deepcopy(), - ticket, - ), - ); - return primitive; - } else if (Array.isArray(value)) { - const array = CRDTArray.create(ticket); - const clone = array.deepcopy(); - target.insertAfter(prevCreatedAt, clone); - context.registerElement(clone, target); - context.push( - AddOperation.create( - target.getCreatedAt(), - prevCreatedAt, - array.deepcopy(), - ticket, - ), - ); - for (const element of value) { - ArrayProxy.pushInternal(context, clone, element); - } - return array; - } else if (typeof value === 'object') { - const obj = CRDTObject.create(ticket); - target.insertAfter(prevCreatedAt, obj); - context.registerElement(obj, target); - context.push( - AddOperation.create( - target.getCreatedAt(), - prevCreatedAt, - obj.deepcopy(), - ticket, - ), - ); - - for (const [k, v] of Object.entries(value!)) { - ObjectProxy.setInternal(context, obj, k, v); - } - return obj; - } - - throw new TypeError(`Unsupported type of value: ${typeof value}`); + const createdAt = context.issueTimeTicket(); + const element = buildCRDTElement(context, value, createdAt); + target.insertAfter(prevCreatedAt, element); + context.registerElement(element, target); + context.push( + AddOperation.create( + target.getCreatedAt(), + prevCreatedAt, + element.deepcopy(), + createdAt, + ), + ); + return element; } /** @@ -579,7 +552,9 @@ export class ArrayProxy { for (let i = from; i < to; i++) { const removed = ArrayProxy.deleteInternalByIndex(context, target, from); if (removed) { - removeds.push(toJSONElement(context, removed)!); + const removedElem = removed.deepcopy(); + removedElem.setRemovedAt(); + removeds.push(toJSONElement(context, removedElem)!); } } if (items) { diff --git a/src/document/json/element.ts b/src/document/json/element.ts index d7c63d8b4..65e679414 100644 --- a/src/document/json/element.ts +++ b/src/document/json/element.ts @@ -28,14 +28,18 @@ import { CRDTCounter, } from '@yorkie-js-sdk/src/document/crdt/counter'; import { CRDTTree } from '@yorkie-js-sdk/src/document/crdt/tree'; +import { RGATreeSplit } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split'; +import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { JSONObject, createJSONObject, + ObjectProxy, } from '@yorkie-js-sdk/src/document/json/object'; import { JSONArray, createJSONArray, + ArrayProxy, } from '@yorkie-js-sdk/src/document/json/array'; import { Text } from '@yorkie-js-sdk/src/document/json/text'; import { Counter } from '@yorkie-js-sdk/src/document/json/counter'; @@ -131,3 +135,45 @@ export function toJSONElement( return wrappedElement; } + +/** + * `buildCRDTElement` constructs a CRDTElement from the given value. + */ +export function buildCRDTElement( + context: ChangeContext, + value: unknown, + createdAt: TimeTicket, +): CRDTElement { + let element: CRDTElement; + if (Primitive.isSupport(value)) { + element = Primitive.of(value as PrimitiveValue, createdAt); + } else if (Array.isArray(value)) { + element = CRDTArray.create( + createdAt, + ArrayProxy.buildArrayElements(context, value), + ); + } else if (typeof value === 'object') { + if (value instanceof Text) { + element = CRDTText.create(RGATreeSplit.create(), createdAt); + value.initialize(context, element as CRDTText); + } else if (value instanceof Counter) { + element = CRDTCounter.create( + value.getValueType(), + value.getValue(), + createdAt, + ); + value.initialize(context, element as CRDTCounter); + } else if (value instanceof Tree) { + element = CRDTTree.create(value.buildRoot(context), createdAt); + value.initialize(context, element as CRDTTree); + } else { + element = CRDTObject.create( + createdAt, + ObjectProxy.buildObjectMembers(context, value!), + ); + } + } else { + throw new TypeError(`Unsupported type of value: ${typeof value}`); + } + return element; +} diff --git a/src/document/json/object.ts b/src/document/json/object.ts index e60cc4704..e594d13da 100644 --- a/src/document/json/object.ts +++ b/src/document/json/object.ts @@ -22,20 +22,10 @@ import { RemoveOperation } from '@yorkie-js-sdk/src/document/operation/remove_op import { ChangeContext } from '@yorkie-js-sdk/src/document/change/context'; import { CRDTElement } from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; -import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; import { - Primitive, - PrimitiveValue, -} from '@yorkie-js-sdk/src/document/crdt/primitive'; -import { RGATreeSplit } from '@yorkie-js-sdk/src/document/crdt/rga_tree_split'; -import { CRDTText } from '@yorkie-js-sdk/src/document/crdt/text'; -import { ArrayProxy } from '@yorkie-js-sdk/src/document/json/array'; -import { Text } from '@yorkie-js-sdk/src/document/json/text'; -import { toJSONElement } from '@yorkie-js-sdk/src/document/json/element'; -import { CRDTCounter } from '@yorkie-js-sdk/src/document/crdt/counter'; -import { Counter } from '@yorkie-js-sdk/src/document/json/counter'; -import { CRDTTree } from '@yorkie-js-sdk/src/document/crdt/tree'; -import { Tree } from '@yorkie-js-sdk/src/document/json/tree'; + toJSONElement, + buildCRDTElement, +} from '@yorkie-js-sdk/src/document/json/element'; /** * `JSONObject` represents a JSON object, but unlike regular JSON, it has time @@ -155,103 +145,47 @@ export class ObjectProxy { ); } - const ticket = context.issueTimeTicket(); - - const setAndRegister = function (elem: CRDTElement) { - const removed = target.set(key, elem, ticket); - context.registerElement(elem, target); - if (removed) { - context.registerRemovedElement(removed); - } - }; + const createdAt = context.issueTimeTicket(); + const element = buildCRDTElement(context, value, createdAt); + const removed = target.set(key, element, createdAt); + context.registerElement(element, target); + if (removed) { + context.registerRemovedElement(removed); + } + context.push( + SetOperation.create( + key, + element.deepcopy(), + target.getCreatedAt(), + createdAt, + ), + ); + } - if (Primitive.isSupport(value)) { - const primitive = Primitive.of(value as PrimitiveValue, ticket); - setAndRegister(primitive); - context.push( - SetOperation.create( - key, - primitive.deepcopy(), - target.getCreatedAt(), - ticket, - ), - ); - } else if (Array.isArray(value)) { - const array = CRDTArray.create(ticket); - setAndRegister(array); - context.push( - SetOperation.create( - key, - array.deepcopy(), - target.getCreatedAt(), - ticket, - ), - ); - for (const element of value) { - ArrayProxy.pushInternal(context, array, element); - } - } else if (typeof value === 'object') { - if (value instanceof Text) { - const text = CRDTText.create(RGATreeSplit.create(), ticket); - target.set(key, text, ticket); - context.registerElement(text, target); - context.push( - SetOperation.create( - key, - text.deepcopy(), - target.getCreatedAt(), - ticket, - ), - ); - value.initialize(context, text); - } else if (value instanceof Counter) { - const counter = CRDTCounter.create( - value.getValueType(), - value.getValue(), - ticket, - ); - target.set(key, counter, ticket); - context.registerElement(counter, target); - context.push( - SetOperation.create( - key, - counter.deepcopy(), - target.getCreatedAt(), - ticket, - ), - ); - value.initialize(context, counter); - } else if (value instanceof Tree) { - const tree = CRDTTree.create(value.buildRoot(context), ticket); - target.set(key, tree, ticket); - context.registerElement(tree, target); - context.push( - SetOperation.create( - key, - tree.deepcopy(), - target.getCreatedAt(), - ticket, - ), - ); - value.initialize(context, tree); - } else { - const obj = CRDTObject.create(ticket); - setAndRegister(obj); - context.push( - SetOperation.create( - key, - obj.deepcopy(), - target.getCreatedAt(), - ticket, - ), + /** + * `buildObjectMembers` constructs an object where all values from the + * user-provided object are transformed into CRDTElements. + * This function takes an object and iterates through its values, + * converting each value into a corresponding CRDTElement. + */ + public static buildObjectMembers( + context: ChangeContext, + value: object, + ): { [key: string]: CRDTElement } { + const members: { [key: string]: CRDTElement } = {}; + for (const [k, v] of Object.entries(value)) { + if (k.includes('.')) { + throw new YorkieError( + Code.InvalidObjectKey, + `key must not contain the '.'.`, ); - for (const [k, v] of Object.entries(value!)) { - ObjectProxy.setInternal(context, obj, k, v); - } } - } else { - logger.fatal(`unsupported type of value: ${typeof value}`); + + const createdAt = context.issueTimeTicket(); + const elem = buildCRDTElement(context, v, createdAt); + members[k] = elem; } + return members; } /** diff --git a/src/document/operation/add_operation.ts b/src/document/operation/add_operation.ts index 8a732e034..ec7208677 100644 --- a/src/document/operation/add_operation.ts +++ b/src/document/operation/add_operation.ts @@ -69,6 +69,7 @@ export class AddOperation extends Operation { const value = this.value.deepcopy(); array.insertAfter(this.prevCreatedAt, value); root.registerElement(value, array); + return { opInfos: [ { @@ -91,7 +92,7 @@ export class AddOperation extends Operation { * `toTestString` returns a string containing the meta data. */ public toTestString(): string { - return `${this.getParentCreatedAt().toTestString()}.ADD`; + return `${this.getParentCreatedAt().toTestString()}.ADD.${this.value.toJSON()}`; } /** diff --git a/src/document/operation/remove_operation.ts b/src/document/operation/remove_operation.ts index 49c41bee3..5e88da410 100644 --- a/src/document/operation/remove_operation.ts +++ b/src/document/operation/remove_operation.ts @@ -23,7 +23,10 @@ import { OperationInfo, ExecutionResult, } from '@yorkie-js-sdk/src/document/operation/operation'; -import { CRDTContainer } from '@yorkie-js-sdk/src/document/crdt/element'; +import { + CRDTContainer, + CRDTElement, +} from '@yorkie-js-sdk/src/document/crdt/element'; import { CRDTObject } from '@yorkie-js-sdk/src/document/crdt/object'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; import { SetOperation } from '@yorkie-js-sdk/src/document/operation/set_operation'; @@ -61,32 +64,34 @@ export class RemoveOperation extends Operation { root: CRDTRoot, source: OpSource, ): ExecutionResult | undefined { - const parentObject = root.findByCreatedAt( + const container = root.findByCreatedAt( this.getParentCreatedAt(), ) as CRDTContainer; - if (!parentObject) { + if (!container) { logger.fatal(`fail to find ${this.getParentCreatedAt()}`); } - if (!(parentObject instanceof CRDTContainer)) { - logger.fatal(`only object and array can execute remove: ${parentObject}`); + if (!(container instanceof CRDTContainer)) { + logger.fatal(`only object and array can execute remove: ${container}`); } // NOTE(chacha912): Handle cases where operation cannot be executed during undo and redo. - const targetElem = parentObject.getByID(this.createdAt); - if ( - source === OpSource.UndoRedo && - (parentObject.getRemovedAt() || !targetElem || targetElem.isRemoved()) - ) { - return; + if (source === OpSource.UndoRedo) { + let parent: CRDTElement | undefined = container.getByID(this.createdAt); + while (parent) { + if (parent.getRemovedAt()) { + return; + } + parent = root.findElementPairByCreatedAt(parent.getCreatedAt())?.parent; + } } - const key = parentObject.subPathOf(this.createdAt); - const reverseOp = this.toReverseOperation(parentObject); + const key = container.subPathOf(this.createdAt); + const reverseOp = this.toReverseOperation(container); - const elem = parentObject.delete(this.createdAt, this.getExecutedAt()); + const elem = container.delete(this.createdAt, this.getExecutedAt()); root.registerRemovedElement(elem); const opInfos: Array = - parentObject instanceof CRDTArray + container instanceof CRDTArray ? [ { type: 'remove', diff --git a/src/document/operation/set_operation.ts b/src/document/operation/set_operation.ts index 74ae9eb91..8d01db463 100644 --- a/src/document/operation/set_operation.ts +++ b/src/document/operation/set_operation.ts @@ -64,23 +64,38 @@ export class SetOperation extends Operation { root: CRDTRoot, source: OpSource, ): ExecutionResult | undefined { - const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); - if (!parentObject) { + const obj = root.findByCreatedAt(this.getParentCreatedAt()) as CRDTObject; + if (!obj) { logger.fatal(`fail to find ${this.getParentCreatedAt()}`); } - if (!(parentObject instanceof CRDTObject)) { + if (!(obj instanceof CRDTObject)) { logger.fatal(`fail to execute, only object can execute set`); } - const obj = parentObject as CRDTObject; + // NOTE(chacha912): Handle cases where operation cannot be executed during undo and redo. - if (source === OpSource.UndoRedo && obj.getRemovedAt()) { - return; + if (source === OpSource.UndoRedo) { + let parent: CRDTElement | undefined = obj; + while (parent) { + if (parent.getRemovedAt()) { + return; + } + parent = root.findElementPairByCreatedAt(parent.getCreatedAt())?.parent; + } } const previousValue = obj.get(this.key); const reverseOp = this.toReverseOperation(previousValue); const value = this.value.deepcopy(); const removed = obj.set(this.key, value, this.getExecutedAt()); + // NOTE(chacha912): When resetting elements with the pre-existing createdAt + // during undo/redo, it's essential to handle previously tombstoned elements. + // In non-GC languages, there may be a need to execute both deregister and purge. + if ( + source === OpSource.UndoRedo && + root.findByCreatedAt(value.getCreatedAt()) + ) { + root.deregisterElement(value); + } root.registerElement(value, obj); if (removed) { root.registerRemovedElement(removed); @@ -108,9 +123,6 @@ export class SetOperation extends Operation { ); if (value !== undefined && !value.isRemoved()) { - // TODO(chacha912): When the value is an object, - // it always sets as an empty object from the remote. - // (Refer to https://github.com/yorkie-team/yorkie/issues/663) reverseOp = SetOperation.create( this.key, value.deepcopy(), diff --git a/test/integration/document_test.ts b/test/integration/document_test.ts index b885c8940..066c1679c 100644 --- a/test/integration/document_test.ts +++ b/test/integration/document_test.ts @@ -158,9 +158,6 @@ describe('Document', function () { expectedEventValue = [ { type: 'set', path: '$', key: 'counter' }, { type: 'set', path: '$', key: 'todos' }, - { type: 'add', path: '$.todos', index: 0 }, - { type: 'add', path: '$.todos', index: 1 }, - { type: 'add', path: '$.todos', index: 2 }, { type: 'set', path: '$', key: 'content' }, { type: 'edit', @@ -173,16 +170,7 @@ describe('Document', function () { path: '$.content', }, { type: 'set', path: '$', key: 'obj' }, - { type: 'set', path: '$.obj', key: 'name' }, - { type: 'set', path: '$.obj', key: 'age' }, - { type: 'set', path: '$.obj', key: 'food' }, - { type: 'add', path: '$.obj.food', index: 0 }, - { type: 'add', path: '$.obj.food', index: 1 }, - { type: 'set', path: '$.obj', key: 'score' }, - { type: 'set', path: '$.obj.score', key: 'english' }, - { type: 'set', path: '$.obj.score', key: 'math' }, { type: 'set', path: '$.obj', key: 'score' }, - { type: 'set', path: '$.obj.score', key: 'science' }, { type: 'remove', path: '$.obj', key: 'food' }, ]; await eventCollectorD1.waitAndVerifyNthEvent(1, { @@ -277,12 +265,6 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(1, [ { type: 'set', path: '$', key: 'counter' }, { type: 'set', path: '$', key: 'todos' }, - { type: 'add', path: '$.todos', index: 0 }, - { type: 'add', path: '$.todos', index: 1 }, - ]); - await eventCollectorForTodos.waitAndVerifyNthEvent(1, [ - { type: 'add', path: '$.todos', index: 0 }, - { type: 'add', path: '$.todos', index: 1 }, ]); d2.update((root) => { @@ -301,7 +283,7 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(3, [ { type: 'add', path: '$.todos', index: 2 }, ]); - await eventCollectorForTodos.waitAndVerifyNthEvent(2, [ + await eventCollectorForTodos.waitAndVerifyNthEvent(1, [ { type: 'add', path: '$.todos', index: 2 }, ]); @@ -312,7 +294,7 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(4, [ { type: 'add', path: '$.todos', index: 3 }, ]); - assert.equal(eventCollectorForTodos.getLength(), 2); // No events after unsubscribing `$.todos` + assert.equal(eventCollectorForTodos.getLength(), 1); // No events after unsubscribing `$.todos` unsubCounter(); d2.update((root) => { @@ -374,21 +356,7 @@ describe('Document', function () { }); await eventCollector.waitAndVerifyNthEvent(1, [ { type: 'set', path: '$', key: 'todos' }, - { type: 'add', path: '$.todos', index: 0 }, - { type: 'set', path: '$.todos.0', key: 'text' }, - { type: 'set', path: '$.todos.0', key: 'completed' }, { type: 'set', path: '$', key: 'obj' }, - { type: 'set', path: '$.obj', key: 'c1' }, - { type: 'set', path: '$.obj.c1', key: 'name' }, - { type: 'set', path: '$.obj.c1', key: 'age' }, - ]); - await eventCollectorForTodos0.waitAndVerifyNthEvent(1, [ - { type: 'set', path: '$.todos.0', key: 'text' }, - { type: 'set', path: '$.todos.0', key: 'completed' }, - ]); - await eventCollectorForObjC1.waitAndVerifyNthEvent(1, [ - { type: 'set', path: '$.obj.c1', key: 'name' }, - { type: 'set', path: '$.obj.c1', key: 'age' }, ]); d2.update((root) => { @@ -397,7 +365,7 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(2, [ { type: 'set', path: '$.obj.c1', key: 'name' }, ]); - await eventCollectorForObjC1.waitAndVerifyNthEvent(2, [ + await eventCollectorForObjC1.waitAndVerifyNthEvent(1, [ { type: 'set', path: '$.obj.c1', key: 'name' }, ]); @@ -407,7 +375,7 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(3, [ { type: 'set', path: '$.todos.0', key: 'completed' }, ]); - await eventCollectorForTodos0.waitAndVerifyNthEvent(2, [ + await eventCollectorForTodos0.waitAndVerifyNthEvent(1, [ { type: 'set', path: '$.todos.0', key: 'completed' }, ]); @@ -418,7 +386,7 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(4, [ { type: 'set', path: '$.todos.0', key: 'text' }, ]); - assert.equal(eventCollectorForTodos0.getLength(), 2); // No events after unsubscribing `$.todos.0` + assert.equal(eventCollectorForTodos0.getLength(), 1); // No events after unsubscribing `$.todos.0` unsubObj(); d2.update((root) => { @@ -427,7 +395,7 @@ describe('Document', function () { await eventCollector.waitAndVerifyNthEvent(5, [ { type: 'set', path: '$.obj.c1', key: 'age' }, ]); - assert.equal(eventCollectorForObjC1.getLength(), 2); // No events after unsubscribing `$.obj.c1` + assert.equal(eventCollectorForObjC1.getLength(), 1); // No events after unsubscribing `$.obj.c1` unsub(); await c1.detach(d1); diff --git a/test/integration/gc_test.ts b/test/integration/gc_test.ts index 358a34bf6..48b17052a 100644 --- a/test/integration/gc_test.ts +++ b/test/integration/gc_test.ts @@ -1,12 +1,11 @@ import { describe, it, assert } from 'vitest'; import { MaxTimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTArray } from '@yorkie-js-sdk/src/document/crdt/array'; -import yorkie, { Tree } from '@yorkie-js-sdk/src/yorkie'; +import yorkie, { Text, Tree } from '@yorkie-js-sdk/src/yorkie'; import { testRPCAddr, toDocKey, } from '@yorkie-js-sdk/test/integration/integration_helper'; -import { Text } from '@yorkie-js-sdk/src/yorkie'; import { CRDTTreeNode } from '@yorkie-js-sdk/src/document/crdt/tree'; import { IndexTreeNode } from '@yorkie-js-sdk/src/util/index_tree'; @@ -610,6 +609,34 @@ describe('Garbage Collection', function () { assert.equal(doc.getGarbageLenFromClone(), 6); }); + it('Can collect removed elements from both root and clone for nested array', async function ({ + task, + }) { + type TestDoc = { list: Array> }; + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc = new yorkie.Document(docKey); + const cli = new yorkie.Client(testRPCAddr); + await cli.activate(); + + await cli.attach(doc, { isRealtimeSync: false }); + doc.update((root) => { + root.list = [0, 1, 2]; + root.list.push([3, 4, 5]); + }); + assert.equal('{"list":[0,1,2,[3,4,5]]}', doc.toJSON()); + doc.update((root) => { + delete root.list[1]; + }); + assert.equal('{"list":[0,2,[3,4,5]]}', doc.toJSON()); + doc.update((root) => { + delete (root.list[2] as Array)[1]; + }); + assert.equal('{"list":[0,2,[3,5]]}', doc.toJSON()); + + assert.equal(doc.getGarbageLen(), 2); + assert.equal(doc.getGarbageLenFromClone(), 2); + }); + it('Can purges removed elements after peers can not access them', async function ({ task, }) { diff --git a/test/integration/object_test.ts b/test/integration/object_test.ts index 40e9411b3..b551a5ba7 100644 --- a/test/integration/object_test.ts +++ b/test/integration/object_test.ts @@ -246,14 +246,14 @@ describe('Object', function () { assert.equal(doc.toSortedJSON(), '{"shape":{"color":"black"}}'); assert.deepEqual( doc.getUndoStackForTest().at(-1)?.map(toStringHistoryOp), - ['1:00:1.REMOVE.1:00:2', '0:00:0.REMOVE.1:00:1'], + ['0:00:0.REMOVE.1:00:1'], ); doc.history.undo(); assert.equal(doc.toSortedJSON(), `{}`); assert.deepEqual( doc.getRedoStackForTest().at(-1)?.map(toStringHistoryOp), - ['0:00:0.SET.shape={}', '1:00:1.SET.color="black"'], + ['0:00:0.SET.shape={"color":"black"}'], ); doc.history.redo(); @@ -363,7 +363,7 @@ describe('Object', function () { assertUndoRedo(doc, states); }); - it.skip(`Should ensure convergence of peer's document after undoing nested objects`, async function ({ + it(`Should ensure convergence of peer's document after undoing nested objects`, async function ({ task, }) { // Test scenario: @@ -404,11 +404,10 @@ describe('Object', function () { assert.equal(doc1.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); await client1.sync(); await client2.sync(); - // TODO(chacha912): fix test - assert.equal(doc2.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); // as-is: {"shape":{"point":{}}} + assert.equal(doc2.toSortedJSON(), '{"shape":{"point":{"x":0,"y":0}}}'); }); - it(`Should handle reverse (set) operation targeting elements deleted by other peers`, async function ({ + it(`Should handle reverse set operation for elements that other peers deleted`, async function ({ task, }) { // Test scenario: @@ -455,12 +454,80 @@ describe('Object', function () { assert.equal(doc1.toSortedJSON(), '{}'); assert.equal(doc1.getRedoStackForTest().length, 0); assert.equal(doc1.history.canRedo(), false); + }); + + it(`Should handle reverse set operation for elements (nested objects) that other peers deleted`, async function ({ + task, + }) { + // Test scenario: + // c1: create shape + // c1: set shape.circle.point to { x: 1, y: 1 } + // c2: delete shape + // c1: undo(no changes as the shape was deleted) + interface TestDoc { + shape?: { circle: { point: { x: number; y: number } } }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + doc1.update((root) => { + root.shape = { circle: { point: { x: 0, y: 0 } } }; + }); + await client1.sync(); + assert.equal( + doc1.toSortedJSON(), + '{"shape":{"circle":{"point":{"x":0,"y":0}}}}', + ); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal( + doc2.toSortedJSON(), + '{"shape":{"circle":{"point":{"x":0,"y":0}}}}', + ); + + doc1.update((root) => { + root.shape!.circle.point = { x: 1, y: 1 }; + }); await client1.sync(); await client2.sync(); + assert.equal( + doc1.toSortedJSON(), + '{"shape":{"circle":{"point":{"x":1,"y":1}}}}', + ); + assert.equal( + doc2.toSortedJSON(), + '{"shape":{"circle":{"point":{"x":1,"y":1}}}}', + ); + doc2.update((root) => { + delete root.shape; + }, 'delete shape'); + await client2.sync(); await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc2.toSortedJSON(), '{}'); + + const c1ID = client1.getID()!.slice(-2); + assert.deepEqual( + doc1.getUndoStackForTest().at(-1)?.map(toStringHistoryOp), + [`2:${c1ID}:2.SET.point={"x":0,"y":0}`], + ); + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{}'); + await client1.sync(); + await client2.sync(); + assert.equal(doc2.toSortedJSON(), '{}'); + assert.equal(doc1.getRedoStackForTest().length, 0); + assert.equal(doc1.history.canRedo(), false); }); - it(`Should handle reverse (remove) operation targeting elements deleted by other peers`, async function ({ + it(`Should handle reverse remove operation for elements that other peers deleted`, async function ({ task, }) { // Test scenario: @@ -497,6 +564,127 @@ describe('Object', function () { assert.equal(doc1.toSortedJSON(), '{}'); assert.equal(doc2.toSortedJSON(), '{}'); + // c2 deleted the shape, so the reverse operation cannot be applied + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc1.getRedoStackForTest().length, 0); + assert.equal(doc1.history.canRedo(), false); + }); + + it(`Should handle reverse remove operation for elements (nested objects) that other peers deleted`, async function ({ + task, + }) { + // Test scenario: + // c1: set shape.circle.point to { x: 0, y: 0 } + // c2: delete shape + // c1: undo(no changes as the shape was deleted) + interface TestDoc { + shape?: { + circle?: { point?: { x?: number; y?: number }; color?: string }; + }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + doc1.update((root) => { + root.shape = { circle: { color: 'red' } }; + }); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"circle":{"color":"red"}}}'); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal(doc2.toSortedJSON(), '{"shape":{"circle":{"color":"red"}}}'); + + doc1.update((root) => { + root.shape!.circle!.point = { x: 0, y: 0 }; + }); + await client1.sync(); + await client2.sync(); + assert.equal( + doc1.toSortedJSON(), + '{"shape":{"circle":{"color":"red","point":{"x":0,"y":0}}}}', + ); + assert.equal( + doc2.toSortedJSON(), + '{"shape":{"circle":{"color":"red","point":{"x":0,"y":0}}}}', + ); + doc2.update((root) => { + delete root.shape; + }, 'delete shape'); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc2.toSortedJSON(), '{}'); + + const c1ID = client1.getID()!.slice(-2); + assert.deepEqual( + doc1.getUndoStackForTest().at(-1)?.map(toStringHistoryOp), + [`2:${c1ID}:2.REMOVE.3:${c1ID}:1`], + ); + doc1.history.undo(); + assert.equal(doc1.toSortedJSON(), '{}'); + await client1.sync(); + await client2.sync(); + assert.equal(doc2.toSortedJSON(), '{}'); + assert.deepEqual(doc1.getRedoStackForTest().length, 0); + }); + + it(`Should not propagate changes when there is no applied undo operation`, async function ({ + task, + }) { + interface TestDoc { + shape?: { color: string }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + let doc1ChangeID = doc1.getChangeID(); + let doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 1); + assert.equal(doc1Checkpoint.getClientSeq(), 1); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 1); + + doc1.update((root) => { + root.shape = { color: 'black' }; + }, 'init doc'); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"black"}}'); + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 2); + + await client2.attach(doc2, { isRealtimeSync: false }); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"black"}}'); + + doc2.update((root) => { + delete root.shape; + }, 'delete shape'); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{}'); + assert.equal(doc2.toSortedJSON(), '{}'); + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 4); + // c2 deleted the shape, so the reverse operation cannot be applied doc1.history.undo(); assert.equal(doc1.toSortedJSON(), '{}'); @@ -505,6 +693,23 @@ describe('Object', function () { await client1.sync(); await client2.sync(); await client1.sync(); + // Since there are no applied operations, there should be no change in the sequence. + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getClientSeq(), 2); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 4); + + doc1.update((root) => { + root.shape = { color: 'red' }; + }); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"red"}}'); + doc1ChangeID = doc1.getChangeID(); + doc1Checkpoint = doc1.getCheckpoint(); + assert.equal(doc1ChangeID.getClientSeq(), 3); + assert.equal(doc1Checkpoint.getClientSeq(), 3); + assert.equal(doc1Checkpoint.getServerSeq().toInt(), 5); }); it(`Should not propagate changes when there is no applied undo operation`, async function ({ @@ -739,5 +944,50 @@ describe('Object', function () { await client2.sync(); assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"red"}}'); }); + + it(`Should clean up the references to a previously deleted node when the deleted node is restored through undo`, async function ({ + task, + }) { + interface TestDoc { + shape: { color: string }; + } + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new Document(docKey); + const doc2 = new Document(docKey); + + const client1 = new Client(testRPCAddr); + const client2 = new Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + await client1.attach(doc1, { isRealtimeSync: false }); + await client2.attach(doc2, { isRealtimeSync: false }); + + doc1.update((root) => { + root.shape = { color: 'black' }; + }); + await client1.sync(); + await client2.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"black"}}'); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"black"}}'); + + doc2.update((root) => { + root.shape = { color: 'yellow' }; + }); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"yellow"}}'); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"yellow"}}'); + + doc2.history.undo(); + await client2.sync(); + await client1.sync(); + assert.equal(doc1.toSortedJSON(), '{"shape":{"color":"black"}}'); + assert.equal(doc2.toSortedJSON(), '{"shape":{"color":"black"}}'); + + // NOTE(chacha912): removedElementSetByCreatedAt should only retain + // the entry for `{shape: {color: 'yellow'}}`. + assert.equal(doc2.getGarbageLen(), 2); + }); }); }); From 3eac1aa7f8161146245b75bde6b6005213e5c0d0 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Sat, 25 Nov 2023 15:15:05 +0900 Subject: [PATCH 06/48] Update CHANGELOG.md for v0.4.9 (#693) --- CHANGELOG.md | 15 +++++++++++++++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13a10d430..b74528d20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +## [0.4.9] - 2023-11-25 + +### Added +* Implement merge elements in `Tree.Edit` by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/681 +* Add README and thumbnail on example 'simultaneous-cursors'by @banma1234 in https://github.com/yorkie-team/yorkie-js-sdk/pull/683 +* Support Undo/Redo for object.set and object.remove operations by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/658 + +### Changed +* Refactor ProseMirror example and Tree codes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/686 +* Enhance Set and Add for representing nested elements by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/691 + +### Fixed +* Add missing `removedAt` during Primitive deepcopy by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/692 +* Prevent empty ops are applied during undo/redo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/687 + ## [0.4.8] - 2023-11-01 ### Changed diff --git a/package.json b/package.json index a71539c26..707b0d476 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.8", + "version": "0.4.9", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index 8b58a23db..07d1bf5b4 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.8", + "version": "0.4.9", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From e11047d930c1c4895beacf4ff1f3db5e45364829 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Sat, 25 Nov 2023 15:24:13 +0900 Subject: [PATCH 07/48] Add permissions for provenance --- .github/workflows/npm-publish.yml | 3 +++ package-lock.json | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index d2c556ec4..57cd1dcf5 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -5,6 +5,9 @@ on: jobs: build: runs-on: ubuntu-latest + permissions: + contents: read + id-token: write steps: - name: Checkout 🛎️ uses: actions/checkout@v2 diff --git a/package-lock.json b/package-lock.json index c19dfe2ee..d5cbbdd28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "yorkie-js-sdk", - "version": "0.4.7", + "version": "0.4.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "yorkie-js-sdk", - "version": "0.4.7", + "version": "0.4.9", "license": "Apache-2.0", "workspaces": [ "examples/*" From 0e34144a4be6d5dc5bc8cb563dfdbf6afb850c00 Mon Sep 17 00:00:00 2001 From: changhui lee Date: Sat, 25 Nov 2023 22:50:57 +0900 Subject: [PATCH 08/48] Add create-yorkie-app (#690) Provides CLI starter kit to allow npm users to conveniently scaffold yorkie-based cooperative apps --------- Co-authored-by: se030 --- .../workflows/create-yorkie-app-publish.yml | 31 ++ examples/CONTRIBUTING.md | 39 +++ package-lock.json | 79 ++++- package.json | 6 +- tools/README.md | 5 + tools/create-yorkie-app/.env | 2 + tools/create-yorkie-app/MAINTAINING.md | 33 ++ tools/create-yorkie-app/README.md | 30 ++ tools/create-yorkie-app/frameworks.ts | 87 ++++++ tools/create-yorkie-app/index.ts | 282 ++++++++++++++++++ tools/create-yorkie-app/package.json | 27 ++ tools/create-yorkie-app/tsconfig.json | 16 + tools/create-yorkie-app/webpack.config.js | 64 ++++ 13 files changed, 696 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/create-yorkie-app-publish.yml create mode 100644 examples/CONTRIBUTING.md create mode 100644 tools/README.md create mode 100644 tools/create-yorkie-app/.env create mode 100644 tools/create-yorkie-app/MAINTAINING.md create mode 100644 tools/create-yorkie-app/README.md create mode 100644 tools/create-yorkie-app/frameworks.ts create mode 100644 tools/create-yorkie-app/index.ts create mode 100644 tools/create-yorkie-app/package.json create mode 100644 tools/create-yorkie-app/tsconfig.json create mode 100644 tools/create-yorkie-app/webpack.config.js diff --git a/.github/workflows/create-yorkie-app-publish.yml b/.github/workflows/create-yorkie-app-publish.yml new file mode 100644 index 000000000..4c6eaa483 --- /dev/null +++ b/.github/workflows/create-yorkie-app-publish.yml @@ -0,0 +1,31 @@ +name: create-yorkie-app-publish +on: + workflow_dispatch: + push: + branches: + - main + paths: + - tools/create-yorkie-app/** + - examples/** +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Checkout 🛎️ + uses: actions/checkout@v2 + - name: Setup Node 🔧 + uses: actions/setup-node@v2 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: package-lock.json + registry-url: 'https://registry.npmjs.org' + - run: npm install + - run: cd tools/create-yorkie-app && npm run build + - run: cd tools/create-yorkie-app && npm publish --provenance + continue-on-error: true + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/examples/CONTRIBUTING.md b/examples/CONTRIBUTING.md new file mode 100644 index 000000000..9b53558d1 --- /dev/null +++ b/examples/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# Contributing + +See [CONTRIBUTING.md](../CONTRIBUTING.md) for the general guides for contribution. + +## Keeping create-yorkie-app in sync with examples + +When adding a new example, you have to update create-yorkie-app's [frameworks.ts](../tools//create-yorkie-app/frameworks.ts). + +Add FrameworkVariant to the variants array under appropriate category like: + +```js +export const FRAMEWORKS: Array = [ + { + name: 'vanilla', + display: 'Vanilla', + color: yellow, + variants: [ + { + name: 'vanilla-codemirror6', + display: 'codemirror', + }, + { + name: 'vanilla-quill', + display: 'quill', + }, + { + name: 'profile-stack', + display: 'profile-stack', + }, + // Your yorkie example in Vanilla JS + { + name: 'directory-name', + display: 'display-name', + }, + ], + }, + // ... +]; +``` diff --git a/package-lock.json b/package-lock.json index d5cbbdd28..9138f386a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.4.9", "license": "Apache-2.0", "workspaces": [ - "examples/*" + "examples/*", + "tools/*" ], "dependencies": { "google-protobuf": "^3.19.4", @@ -3443,11 +3444,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.4.2", "dev": true, "license": "MIT" }, + "node_modules/@types/prompts": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.5.tgz", + "integrity": "sha512-TvrzGMCwARi2qqXcD7VmvMvfMP3F7JRQpeEHECK0oufRNZInoBqzd8v/1zksKFE5XW8OOGto/5FsDT8lnpvGRA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "kleur": "^3.0.3" + } + }, "node_modules/@types/prop-types": { "version": "15.7.5", "license": "MIT" @@ -5733,6 +5750,10 @@ "dev": true, "license": "MIT" }, + "node_modules/create-yorkie-app": { + "resolved": "tools/create-yorkie-app", + "link": true + }, "node_modules/crelt": { "version": "1.0.5", "license": "MIT" @@ -8658,6 +8679,21 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -8949,9 +8985,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "license": "MIT" + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { "version": "0.5.5", @@ -9659,6 +9699,19 @@ "resolved": "examples/profile-stack", "link": true }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "license": "MIT", @@ -10660,6 +10713,12 @@ "node": ">= 10" } }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, "node_modules/slash": { "version": "3.0.0", "dev": true, @@ -12730,6 +12789,20 @@ "test/vitest/env": { "name": "vitest-environment-custom-jsdom", "dev": true + }, + "tools/create-yorkie-app": { + "version": "0.0.0", + "license": "MIT", + "bin": { + "create-yorkie-app": "dist/create-yorkie-app.mjs" + }, + "devDependencies": { + "@types/minimist": "^1.2.2", + "@types/prompts": "^2.4.4", + "kolorist": "^1.8.0", + "minimist": "^1.2.8", + "prompts": "^2.4.2" + } } } } diff --git a/package.json b/package.json index 707b0d476..175d93c5e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "build": "webpack --config ./config/webpack.config.js && npm run api-report && npm run prune", "build:proto": "protoc -I=./src/api --js_out=import_style=commonjs:./src/api --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:./src/api ./src/api/yorkie/v1/*.proto", "build:docs": "npm run predoc && api-documenter markdown --input temp --output docs", - "build:examples": "npm run build --workspaces", + "build:examples": "npm run build --workspace examples", + "build:create-yorkie-app": "npm run build --workspace create-yorkie-app", "build:ghpages": "mkdir -p ghpages/examples && cp -r docs ghpages/api-reference && find examples -name 'dist' -type d -exec sh -c 'cp -r {} ghpages/examples/$(basename $(dirname {}))' \\;", "api-report": "api-extractor run --local --verbose --config ./config/api-extractor.json", "prune": "ts-node-script ./scripts/prune-dts.ts --input ./dist/yorkie-js-sdk.d.ts --output ./dist/yorkie-js-sdk.d.ts", @@ -94,6 +95,7 @@ } }, "workspaces": [ - "examples/*" + "examples/*", + "tools/*" ] } diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 000000000..4d52a6dad --- /dev/null +++ b/tools/README.md @@ -0,0 +1,5 @@ +# Tools + +This directory contains tools for yorkie-js-sdk. + +For usage, refer to the README.md of each project. diff --git a/tools/create-yorkie-app/.env b/tools/create-yorkie-app/.env new file mode 100644 index 000000000..f2a7870e4 --- /dev/null +++ b/tools/create-yorkie-app/.env @@ -0,0 +1,2 @@ +VITE_YORKIE_API_ADDR='https://api.yorkie.dev' +VITE_YORKIE_API_KEY= diff --git a/tools/create-yorkie-app/MAINTAINING.md b/tools/create-yorkie-app/MAINTAINING.md new file mode 100644 index 000000000..e5344fc9c --- /dev/null +++ b/tools/create-yorkie-app/MAINTAINING.md @@ -0,0 +1,33 @@ +# Maintaining create-yorkie-app + +This package is an automated tool to scaffold an example project that shows practical usage of yorkie-js-sdk. + +```bash +. +├── MAINTAINING.md +├── README.md +├── frameworks.ts # abstract data object representing examples/ directory +├── index.ts # main script +├── package.json +├── tsconfig.json +└── webpack.config.js +``` + +## Adding a New Example + +Add information about your new example in [frameworks.ts](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/tools/create-yorkie-app/frameworks.ts). + +Choose or create an appropriate category (e.g. vanilla, react, nextjs, vue, ...) and add an object like below to variants array. + +```ts +{ + name: directory_name, + display: displayed_name_in_prompt +} +``` + +## Publishing a New Version + +Update the version in [package.json](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/tools/create-yorkie-app/package.json#L3). + +Publication will be done via [create-yorkie-app-publish.yml](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/.github/workflows/create-yorkie-app-publish.yml) when changes are pushed into main branch. diff --git a/tools/create-yorkie-app/README.md b/tools/create-yorkie-app/README.md new file mode 100644 index 000000000..80a9a107b --- /dev/null +++ b/tools/create-yorkie-app/README.md @@ -0,0 +1,30 @@ +# create-yorkie-app + +## Usage + +You can scaffold yorkie-js-sdk examples by: + +```bash +$ npx create-yorkie-app +``` + +The examples have own local dependencies. So you should install dependencies before running examples. + +```bash +# In the directory of the example. +$ npm install +``` + +Then you can run the examples. + +```bash +# In the directory of the example. +$ npm run dev +``` + +Open the browser and go to the URL that is printed in the terminal. + +## Note + +Yorkie API key or local server is necessary to run each example. +You can create and manage your projects and API keys at [Yorkie Dashboard](https://yorkie.dev/dashboard). If you want to configure your own server, refer to [this README](../../examples/README.md). diff --git a/tools/create-yorkie-app/frameworks.ts b/tools/create-yorkie-app/frameworks.ts new file mode 100644 index 000000000..02816e3ef --- /dev/null +++ b/tools/create-yorkie-app/frameworks.ts @@ -0,0 +1,87 @@ +import { cyan, lightGreen, reset, yellow } from 'kolorist'; + +/** + * @see https://github.com/marvinhagemeister/kolorist#readme + */ +type ColorFunc = (str: string | number) => string; + +export type Framework = { + name: string; + display: string; + color: ColorFunc; + variants: Array; +}; + +type FrameworkVariant = { + /** + * directory name of the example + */ + name: string; + /** + * display name (in prompt) of the example + */ + display: string; +}; + +export const FRAMEWORKS: Array = [ + { + name: 'vanilla', + display: 'Vanilla', + color: yellow, + variants: [ + { + name: 'vanilla-codemirror6', + display: 'codemirror', + }, + { + name: 'vanilla-quill', + display: 'quill', + }, + { + name: 'profile-stack', + display: 'profile-stack', + }, + ], + }, + { + name: 'react', + display: 'React', + color: cyan, + variants: [ + { + name: 'react-tldraw', + display: 'tldraw', + }, + { + name: 'react-todomvc', + display: 'todomvc', + }, + { + name: 'simultaneous-cursors', + display: 'simultaneous-cursors', + }, + ], + }, + { + name: 'nextjs', + display: 'Next.js', + color: reset, + variants: [ + { + name: 'nextjs-scheduler', + display: 'scheduler', + }, + ], + }, + { + name: 'vue', + display: 'Vue', + color: lightGreen, + variants: [ + { + name: 'vuejs-kanban', + display: 'kanban', + }, + ], + }, +]; diff --git a/tools/create-yorkie-app/index.ts b/tools/create-yorkie-app/index.ts new file mode 100644 index 000000000..0dac069d7 --- /dev/null +++ b/tools/create-yorkie-app/index.ts @@ -0,0 +1,282 @@ +#!/usr/bin/env node + +/* eslint-disable jsdoc/require-jsdoc */ + +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import minimist from 'minimist'; +import prompts from 'prompts'; +import { red, reset } from 'kolorist'; +import { type Framework, FRAMEWORKS } from './frameworks'; + +// Avoids autoconversion to number of the project name by defining that the args +// non associated with an option ( _ ) needs to be parsed as a string. See https://github.com/vitejs/vite/pull/4606 +const argv = minimist<{ + t?: string; + template?: string; +}>(process.argv.slice(2), { string: ['_'] }); +const cwd = process.cwd(); + +const renameFiles: Record = { + _gitignore: '.gitignore', +}; + +const TEMPLATES = FRAMEWORKS.map( + (f) => (f.variants && f.variants.map((v) => v.name)) || [f.name], +).reduce((a, b) => a.concat(b), []); + +const defaultTargetDir = 'yorkie-app'; + +async function init() { + const argTargetDir = formatTargetDir(argv._[0]); + const argTemplate = argv.template || argv.t; + + let targetDir = argTargetDir || defaultTargetDir; + const getProjectName = () => + targetDir === '.' ? path.basename(path.resolve()) : targetDir; + + let result: prompts.Answers< + 'projectName' | 'overwrite' | 'packageName' | 'framework' | 'variant' + >; + + try { + result = await prompts( + [ + { + type: argTargetDir ? null : 'text', + name: 'projectName', + message: reset('Project name:'), + initial: defaultTargetDir, + onState: (state) => { + targetDir = formatTargetDir(state.value) || defaultTargetDir; + }, + }, + { + type: () => + !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm', + name: 'overwrite', + message: () => + (targetDir === '.' + ? 'Current directory' + : `Target directory "${targetDir}"`) + + ` is not empty. Remove existing files and continue?`, + }, + { + type: (_, { overwrite }: { overwrite?: boolean }) => { + if (overwrite === false) { + throw new Error(red('✖') + ' Operation cancelled'); + } + return null; + }, + name: 'overwriteChecker', + }, + { + type: () => (isValidPackageName(getProjectName()) ? null : 'text'), + name: 'packageName', + message: reset('Package name:'), + initial: () => toValidPackageName(getProjectName()), + validate: (dir) => + isValidPackageName(dir) || 'Invalid package.json name', + }, + { + type: + argTemplate && TEMPLATES.includes(argTemplate) ? null : 'select', + name: 'framework', + message: + typeof argTemplate === 'string' && !TEMPLATES.includes(argTemplate) + ? reset( + `"${argTemplate}" isn't a valid template. Please choose from below: `, + ) + : reset('Select a framework:'), + initial: 0, + choices: FRAMEWORKS.map((framework) => { + const frameworkColor = framework.color; + return { + title: frameworkColor(framework.display || framework.name), + value: framework, + }; + }), + }, + { + type: (framework: Framework) => + framework && framework.variants ? 'select' : null, + name: 'variant', + message: reset('Select a variant:'), + choices: ({ variants, color }: Framework) => + variants.map((variant) => { + return { + title: color(variant.display || variant.name), + value: variant.name, + }; + }), + }, + ], + { + onCancel: () => { + throw new Error(red('✖') + ' Operation cancelled'); + }, + }, + ); + } catch (cancelled: any) { + console.error(cancelled.message); + return; + } + + // user choice associated with prompts + const { framework, overwrite, packageName, variant } = result; + + const root = path.join(cwd, targetDir); + + if (overwrite) { + emptyDir(root); + } else if (!fs.existsSync(root)) { + fs.mkdirSync(root, { recursive: true }); + } + + // determine template + const template: string = variant || framework?.name || argTemplate; + + const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent); + const pkgManager = pkgInfo ? pkgInfo.name : 'npm'; + + console.log(`\nScaffolding project in ${root}...`); + + const templateDir = path.resolve( + fileURLToPath(import.meta.url), + `../examples/${template}`, + ); + + const write = (file: string, content?: string) => { + const targetPath = path.join(root, renameFiles[file] ?? file); + if (content) { + fs.writeFileSync(targetPath, content); + } else { + copy(path.join(templateDir, file), targetPath); + } + }; + + const files = fs.readdirSync(templateDir); + for (const file of files) { + if (file === 'package.json' || file === '.env.production') { + continue; + } + + if (file === '.env') { + const envVariables = fs.readFileSync(file).toString(); + + write( + file, + envVariables.replace('http://localhost:8080', 'https://api.yorkie.dev'), + ); + continue; + } + + write(file); + } + + const pkg = JSON.parse( + fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8'), + ); + + pkg.name = packageName || getProjectName(); + + write('package.json', JSON.stringify(pkg, null, 2) + '\n'); + + console.log(`\nDone. Now run:\n`); + + const cdProjectName = path.relative(cwd, root); + if (root !== cwd) { + console.log( + ` cd ${ + cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName + }`, + ); + } + + switch (pkgManager) { + case 'yarn': + console.log(' yarn'); + console.log(' yarn dev'); + break; + default: + console.log(` ${pkgManager} install`); + console.log(` ${pkgManager} run dev`); + break; + } + + console.log( + '\n🔑 To run these examples, you need Yorkie API key.' + + `\nGet your API key at https://yorkie.dev/dashboard and put it in ${cdProjectName}/.env`, + ); + console.log(); +} + +function formatTargetDir(targetDir: string | undefined) { + return targetDir?.trim().replace(/\/+$/g, ''); +} + +function copy(src: string, dest: string) { + const stat = fs.statSync(src); + if (stat.isDirectory()) { + copyDir(src, dest); + } else { + fs.copyFileSync(src, dest); + } +} + +function isValidPackageName(projectName: string) { + return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test( + projectName, + ); +} + +function toValidPackageName(projectName: string) { + return projectName + .trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/^[._]/, '') + .replace(/[^a-z\d\-~]+/g, '-'); +} + +function copyDir(srcDir: string, destDir: string) { + fs.mkdirSync(destDir, { recursive: true }); + for (const file of fs.readdirSync(srcDir)) { + const srcFile = path.resolve(srcDir, file); + const destFile = path.resolve(destDir, file); + copy(srcFile, destFile); + } +} + +function isEmpty(path: string) { + const files = fs.readdirSync(path); + return !files.length || !files.filter((file) => !file.startsWith('.')).length; +} + +function emptyDir(dir: string) { + if (!fs.existsSync(dir)) { + return; + } + + for (const file of fs.readdirSync(dir)) { + if (file.startsWith('.')) { + continue; + } + fs.rmSync(path.resolve(dir, file), { recursive: true, force: true }); + } +} + +function pkgFromUserAgent(userAgent: string | undefined) { + if (!userAgent) return undefined; + const pkgSpec = userAgent.split(' ')[0]; + const pkgSpecArr = pkgSpec.split('/'); + return { + name: pkgSpecArr[0], + version: pkgSpecArr[1], + }; +} + +init().catch((e) => { + console.error(e); +}); diff --git a/tools/create-yorkie-app/package.json b/tools/create-yorkie-app/package.json new file mode 100644 index 000000000..b3c365ff4 --- /dev/null +++ b/tools/create-yorkie-app/package.json @@ -0,0 +1,27 @@ +{ + "name": "create-yorkie-app", + "version": "0.4.7", + "bin": { + "create-yorkie-app": "dist/create-yorkie-app.mjs" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "webpack --config ./webpack.config.js && npm run build:copy-assets", + "build:copy-assets": "cp -r ../../examples ./dist && cp ./.env ./dist/.env", + "start": "npm run build && node dist/create-yorkie-app.mjs" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/yorkie-team/yorkie-js-sdk.git" + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/minimist": "^1.2.2", + "@types/prompts": "^2.4.4", + "kolorist": "^1.8.0", + "minimist": "^1.2.8", + "prompts": "^2.4.2" + } +} diff --git a/tools/create-yorkie-app/tsconfig.json b/tools/create-yorkie-app/tsconfig.json new file mode 100644 index 000000000..c5943f647 --- /dev/null +++ b/tools/create-yorkie-app/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "rootDir": ".", + "outDir": "dist", + "target": "ES6", + "module": "ES2020", + "moduleResolution": "node", + "strict": true, + "skipLibCheck": true, + "declaration": false, + "sourceMap": false, + "noUnusedLocals": true, + "esModuleInterop": true + }, + "include": ["*"] +} diff --git a/tools/create-yorkie-app/webpack.config.js b/tools/create-yorkie-app/webpack.config.js new file mode 100644 index 000000000..90e097d81 --- /dev/null +++ b/tools/create-yorkie-app/webpack.config.js @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const path = require('path'); +const webpack = require('webpack'); + +module.exports = { + entry: './index', + mode: 'production', + target: 'node', + optimization: { + minimize: false, + }, + module: { + parser: { + javascript: { + importMeta: false, + }, + }, + rules: [ + { + test: /\.ts$/, + use: { + loader: 'ts-loader', + options: { + configFile: path.resolve(__dirname, './tsconfig.json'), + }, + }, + }, + ], + }, + resolve: { + extensions: ['.ts', '.js'], + }, + output: { + module: true, + chunkFormat: 'module', + filename: 'create-yorkie-app.mjs', + path: path.resolve(__dirname, './dist'), + clean: true, + }, + plugins: [ + new webpack.BannerPlugin({ + banner: '#!/usr/bin/env node', + raw: true, + }), + ], + experiments: { + outputModule: true, + }, +}; From 4bbdf2e83208bb046b11de0279d9735e66b37810 Mon Sep 17 00:00:00 2001 From: changhui lee Date: Sun, 26 Nov 2023 09:20:26 +0900 Subject: [PATCH 09/48] Fix reading wrong .env path (#694) * Fix reading wrong .env path * Update version --- tools/create-yorkie-app/index.ts | 4 +++- tools/create-yorkie-app/package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/create-yorkie-app/index.ts b/tools/create-yorkie-app/index.ts index 0dac069d7..6b908e193 100644 --- a/tools/create-yorkie-app/index.ts +++ b/tools/create-yorkie-app/index.ts @@ -163,7 +163,9 @@ async function init() { } if (file === '.env') { - const envVariables = fs.readFileSync(file).toString(); + const envVariables = fs + .readFileSync(path.join(templateDir, file)) + .toString(); write( file, diff --git a/tools/create-yorkie-app/package.json b/tools/create-yorkie-app/package.json index b3c365ff4..774215c0a 100644 --- a/tools/create-yorkie-app/package.json +++ b/tools/create-yorkie-app/package.json @@ -1,6 +1,6 @@ { "name": "create-yorkie-app", - "version": "0.4.7", + "version": "0.4.7-fix.1", "bin": { "create-yorkie-app": "dist/create-yorkie-app.mjs" }, From 3db9d5907077de3b1b435d212eb2b8aa02e04731 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:18:45 +0900 Subject: [PATCH 10/48] Handle escape string for strings containing quotes (#700) In pull request #330, when implementing the escape string function, it referred to the js-string-escape library. However, we missed a point mentioned in its documentation: > Note that the returned string is not necessarily valid JSON, since JSON > disallows control characters, and \' is illegal in JSON. This caused an error due to the mishandling of single quotes during the escape string process. Since we don't need to handle single quotes specially, we removed that part. Chromium implementation: https://github.com/chromium/chromium/blob/fc0cb60674643692171a84bb94a92c8bf5781031/base/json/string_escape.cc#L33-L79 We also fixed a missing part in handling escape string for object keys. --- src/document/crdt/object.ts | 5 +++-- src/document/crdt/rht.ts | 2 +- src/document/crdt/text.ts | 4 ++-- src/document/json/strings.ts | 1 - test/integration/text_test.ts | 6 +++--- test/unit/document/document_test.ts | 24 ++++++++++++++++++++++++ 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/document/crdt/object.ts b/src/document/crdt/object.ts index a9ca13ee6..0e002256d 100644 --- a/src/document/crdt/object.ts +++ b/src/document/crdt/object.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { escapeString } from '@yorkie-js-sdk/src/document/json/strings'; import { TimeTicket } from '@yorkie-js-sdk/src/document/time/ticket'; import { CRDTContainer, @@ -125,7 +126,7 @@ export class CRDTObject extends CRDTContainer { public toJSON(): string { const json = []; for (const [key, value] of this) { - json.push(`"${key}":${value.toJSON()}`); + json.push(`"${escapeString(key)}":${value.toJSON()}`); } return `{${json.join(',')}}`; } @@ -182,7 +183,7 @@ export class CRDTObject extends CRDTContainer { const json = []; for (const key of keys.sort()) { const node = this.memberNodes.get(key)?.getValue(); - json.push(`"${key}":${node!.toSortedJSON()}`); + json.push(`"${escapeString(key)}":${node!.toSortedJSON()}`); } return `{${json.join(',')}}`; diff --git a/src/document/crdt/rht.ts b/src/document/crdt/rht.ts index e548f9e3b..194579681 100644 --- a/src/document/crdt/rht.ts +++ b/src/document/crdt/rht.ts @@ -125,7 +125,7 @@ export class RHT { public toJSON(): string { const items = []; for (const [key, node] of this.nodeMapByKey) { - items.push(`"${key}":"${escapeString(node.getValue())}"`); + items.push(`"${escapeString(key)}":"${escapeString(node.getValue())}"`); } return `{${items.join(',')}}`; } diff --git a/src/document/crdt/text.ts b/src/document/crdt/text.ts index ee42dd8f3..3fd3ca85b 100644 --- a/src/document/crdt/text.ts +++ b/src/document/crdt/text.ts @@ -131,8 +131,8 @@ export class CRDTTextValue { const value = JSON.parse(v); const item = typeof value === 'string' - ? `"${key}":"${escapeString(value)}"` - : `"${key}":${String(value)}`; + ? `"${escapeString(key)}":"${escapeString(value)}"` + : `"${escapeString(key)}":${String(value)}`; attrs.push(item); } attrs.sort(); diff --git a/src/document/json/strings.ts b/src/document/json/strings.ts index 67e10f74a..cb32304ab 100644 --- a/src/document/json/strings.ts +++ b/src/document/json/strings.ts @@ -5,7 +5,6 @@ export function escapeString(str: string): string { return str.replace(/["'\\\n\r\f\b\t\u2028\u2029]/g, function (character) { switch (character) { case '"': - case "'": case '\\': return '\\' + character; case '\n': diff --git a/test/integration/text_test.ts b/test/integration/text_test.ts index cb08dc344..3fbe1e93f 100644 --- a/test/integration/text_test.ts +++ b/test/integration/text_test.ts @@ -707,14 +707,14 @@ describe('peri-text example: text concurrent edit', function () { }, `add comment by c1`); assert.equal( d1.toSortedJSON(), - `{"k1":[{"attrs":{"comment":"Alice\\'s comment"},"val":"The fox"},{"val":" jumped."}]}`, + `{"k1":[{"attrs":{"comment":"Alice's comment"},"val":"The fox"},{"val":" jumped."}]}`, ); d2.update((root) => { root.k1.setStyle(4, 15, { comment: `Bob's comment` }); }, `add comment by c2`); assert.equal( d2.toSortedJSON(), - `{"k1":[{"val":"The "},{"attrs":{"comment":"Bob\\'s comment"},"val":"fox jumped."}]}`, + `{"k1":[{"val":"The "},{"attrs":{"comment":"Bob's comment"},"val":"fox jumped."}]}`, ); await c1.sync(); await c2.sync(); @@ -723,7 +723,7 @@ describe('peri-text example: text concurrent edit', function () { // so it would be better we can keep both comments. assert.equal( d1.toSortedJSON(), - `{"k1":[{"attrs":{"comment":"Alice\\'s comment"},"val":"The "},{"attrs":{"comment":"Bob\\'s comment"},"val":"fox"},{"attrs":{"comment":"Bob\\'s comment"},"val":" jumped."}]}`, + `{"k1":[{"attrs":{"comment":"Alice's comment"},"val":"The "},{"attrs":{"comment":"Bob's comment"},"val":"fox"},{"attrs":{"comment":"Bob's comment"},"val":" jumped."}]}`, 'd1', ); assert.equal(d2.toSortedJSON(), d1.toSortedJSON(), 'd2'); diff --git a/test/unit/document/document_test.ts b/test/unit/document/document_test.ts index eb92746ac..e2200a2ad 100644 --- a/test/unit/document/document_test.ts +++ b/test/unit/document/document_test.ts @@ -1228,6 +1228,30 @@ describe.sequential('Document', function () { assert.equal(0, doc.getGarbageLen()); }); + it('should handle escape string for strings containing single quotes', function () { + const doc = new Document<{ [key: string]: any }>('test-doc'); + doc.update((root) => (root.str = `I'm yorkie`)); + assert.equal(doc.toSortedJSON(), `{"str":"I'm yorkie"}`); + assert.deepEqual(JSON.parse(doc.toSortedJSON()), { + str: `I'm yorkie`, + }); + + doc.update((root) => (root.str = `I\\'m yorkie`)); + assert.equal(doc.toSortedJSON(), `{"str":"I\\\\'m yorkie"}`); + assert.deepEqual(JSON.parse(doc.toSortedJSON()), { + str: `I\\'m yorkie`, + }); + }); + + it('should handle escape string for object keys', function () { + const doc = new Document<{ [key: string]: any }>('test-doc'); + doc.update((root) => (root[`it"s`] = `yorkie`)); + assert.equal(doc.toSortedJSON(), `{"it\\"s":"yorkie"}`); + assert.deepEqual(JSON.parse(doc.toSortedJSON()), { + [`it"s`]: `yorkie`, + }); + }); + it('escapes string for object', function () { const doc = new Document<{ a?: string }>('test-doc'); doc.update((root) => { From 41f5b2f0f03848564b106988f957a711ad4eba2b Mon Sep 17 00:00:00 2001 From: Yun Min Woo Date: Thu, 30 Nov 2023 21:13:05 +0900 Subject: [PATCH 11/48] Correct typos in the installation command on README.md in the example (#702) * Fix typo error on examples/nextjs-scheduler's README.md The contents of 'How to run demo' have changed as follows docker-compose up -f ... --> docker-compose -f ... Signed-off-by: ymw0407 * Fix typo error on examples/react-todomvc/README.md The contents of 'How to run demo' have changed as follows docker-compose up -f ... --> docker-compose -f ... Signed-off-by: ymw0407 --- examples/nextjs-scheduler/README.md | 2 +- examples/react-todomvc/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/nextjs-scheduler/README.md b/examples/nextjs-scheduler/README.md index ae133c846..a89828187 100644 --- a/examples/nextjs-scheduler/README.md +++ b/examples/nextjs-scheduler/README.md @@ -13,7 +13,7 @@ At project root, run below command to start Yorkie server and Envoy proxy. ```bash -$ docker-compose up -f docker/docker-compose.yml up --build -d +$ docker-compose -f docker/docker-compose.yml up --build -d ``` Then install dependencies and run the demo. diff --git a/examples/react-todomvc/README.md b/examples/react-todomvc/README.md index a17b4c80f..85583e7fd 100644 --- a/examples/react-todomvc/README.md +++ b/examples/react-todomvc/README.md @@ -13,7 +13,7 @@ At project root, run below command to start Yorkie server and Envoy proxy. ```bash -$ docker-compose up -f docker/docker-compose.yml up --build -d +$ docker-compose -f docker/docker-compose.yml up --build -d ``` Then install dependencies and run the demo. From d0f5aedf6e094e9b24b0d3ff299d5b0c32341ea6 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Fri, 1 Dec 2023 16:02:30 +0900 Subject: [PATCH 12/48] Add `removeIfNotAttached` to `client.detach()` options (#703) --- src/client/client.ts | 4 +++ test/integration/document_test.ts | 50 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/client/client.ts b/src/client/client.ts index d419aa7a0..71a69c57a 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -508,6 +508,9 @@ export class Client implements Observable { */ public detach( doc: Document, + options: { + removeIfNotAttached?: boolean; + } = {}, ): Promise> { if (!this.isActive()) { throw new YorkieError(Code.ClientNotActive, `${this.key} is not active`); @@ -526,6 +529,7 @@ export class Client implements Observable { req.setClientId(this.id!); req.setDocumentId(attachment.docID); req.setChangePack(converter.toChangePack(doc.createChangePack())); + req.setRemoveIfNotAttached(options.removeIfNotAttached ?? false); this.rpcClient.detachDocument( req, diff --git a/test/integration/document_test.ts b/test/integration/document_test.ts index 066c1679c..7d7e4884b 100644 --- a/test/integration/document_test.ts +++ b/test/integration/document_test.ts @@ -56,6 +56,56 @@ describe('Document', function () { await client2.deactivate(); }); + it('Can remove document using removeIfNotAttached option when detaching', async function ({ + task, + }) { + type TestDoc = { k1: Array; k2: Array }; + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new yorkie.Document(docKey); + const doc2 = new yorkie.Document(docKey); + + const client1 = new yorkie.Client(testRPCAddr); + const client2 = new yorkie.Client(testRPCAddr); + await client1.activate(); + await client2.activate(); + + // 1. client1 attaches and updates the document. + await client1.attach(doc1); + assert.equal('{}', doc1.toSortedJSON()); + doc1.update((root) => { + root.k1 = [1, 2]; + root.k2 = [3, 4]; + }); + await client1.sync(); + assert.equal('{"k1":[1,2],"k2":[3,4]}', doc1.toSortedJSON()); + + // 2. client2 attaches the document. + await client2.attach(doc2); + assert.equal('{"k1":[1,2],"k2":[3,4]}', doc2.toSortedJSON()); + + // 3. client1 detaches the document. + // The document is not removed as client2 is still attached to it. + await client1.detach(doc1, { removeIfNotAttached: true }); + assert.equal(doc1.getStatus(), DocumentStatus.Detached); + + // 4. client2 detaches the document. + // Since no client is attached to the document, it gets removed. + await client2.detach(doc2, { removeIfNotAttached: true }); + assert.equal(doc2.getStatus(), DocumentStatus.Removed); + + // 5. client3 attaches the document. + // The content of the removed document should not be exposed. + const doc3 = new yorkie.Document(docKey); + const client3 = new yorkie.Client(testRPCAddr); + await client3.activate(); + await client3.attach(doc3); + assert.equal('{}', doc3.toSortedJSON()); + + await client1.deactivate(); + await client2.deactivate(); + await client3.deactivate(); + }); + it('Can watch documents', async function ({ task }) { const c1 = new yorkie.Client(testRPCAddr); const c2 = new yorkie.Client(testRPCAddr); From 2b0b7f63792a8a26c32e940a8c64aa314f238848 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 4 Dec 2023 21:23:56 +0900 Subject: [PATCH 13/48] Implement splitLevel of Tree.Edit (#704) When a user positions the cursor within a paragraph and hits the enter key, the paragraph is divided into two separate paragraphs: - Original: `

a|b

` - Result: `

a

b

` In this commit, `splitLevel` is introduced to support this scenario. ```ts doc.update((root) => { root.tree.edit([0,0], {type:'p',children:[{type:'text', value: 'ab'}]}); root.tree.edit([2,2], undefined, 1); // split the paragraph }); ``` This commit does not cover all test cases that may arise due to the split operation. This is because we need to verify the interface first. we need to add test cases in the simultaneous editing situation to verify the algorithm later. Tasks: - Refactor Tree.Edit logic to implement splitLevel of Tree.Edit - Remove skip from the unit tests related to splitLevel --- package-lock.json | 4 +- public/prosemirror.html | 66 ++- src/api/converter.ts | 5 +- src/api/yorkie/v1/resources.proto | 8 + src/api/yorkie/v1/resources_pb.d.ts | 35 ++ src/api/yorkie/v1/resources_pb.js | 330 ++++++++++++++- src/api/yorkie/v1/yorkie.proto | 12 + src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts | 12 + src/api/yorkie/v1/yorkie_grpc_web_pb.js | 63 ++- src/api/yorkie/v1/yorkie_pb.d.ts | 46 ++ src/api/yorkie/v1/yorkie_pb.js | 397 +++++++++++++++++- src/document/crdt/tree.ts | 213 ++++++---- src/document/json/tree.ts | 73 +++- src/document/operation/operation.ts | 11 +- src/document/operation/tree_edit_operation.ts | 45 +- src/util/index_tree.ts | 42 +- test/integration/tree_test.ts | 212 +++++----- test/unit/document/crdt/tree_test.ts | 209 +++++---- 18 files changed, 1405 insertions(+), 378 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9138f386a..df80318ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12791,8 +12791,8 @@ "dev": true }, "tools/create-yorkie-app": { - "version": "0.0.0", - "license": "MIT", + "version": "0.4.7-fix.1", + "license": "Apache-2.0", "bin": { "create-yorkie-app": "dist/create-yorkie-app.mjs" }, diff --git a/public/prosemirror.html b/public/prosemirror.html index 0295022d2..62380ed4a 100644 --- a/public/prosemirror.html +++ b/public/prosemirror.html @@ -324,8 +324,8 @@

Yorkie.Tree

} = step; // 01. Move: level up/down, move left/right. - // TODO(hackerwins): replaceAround replaces the given range with given gap. if (stepType === 'replaceAround') { + // TODO(hackerwins): replaceAround replaces the given range with given gap. // root.tree.move(from, to, gapFrom, gapTo); continue; } @@ -334,27 +334,55 @@

Yorkie.Tree

if ( stepType === 'replace' && openStart && - openEnd && + openStart === openEnd && structure ) { - // TODO(hackerwins): edit should support openStart and openEnd. - // root.tree.edit(from, to, docToTreeNode(node.toJSON()), [ - // openStart, - // openEnd, - // ]); + // TODO(hackerwins): we need to handle more step cases. + // - 1. openStart and openEnd can be assymetric. + // - 2. content.content could be more than three. + root.tree.edit( + from, + to, + content.content.length == 3 + ? docToTreeNode(content.content[1]) + : undefined, + openStart, + ); + console.log( + `%c local: ${from}-${to}: split(${openStart})`, + 'color: green', + ); continue; } // 03. Edit: Delete the given range. if (!content.content.length) { root.tree.edit(from, to); + console.log( + `%c local: ${from}-${to}: delete)`, + 'color: green', + ); continue; } // 04. Edit: Replace the given range with the given content. - for (const node of content.content) { - root.tree.edit(from, to, docToTreeNode(node.toJSON())); - } + // + // TODO(hackerwins): We need to handle unary element. + // Unary element is a node that has no children. For example, . + // + // TODO(hackerwins): We need to handle select all and replace. + // There is an issue when we replace the whole document in ProseMirror. + root.tree.editBulk( + from, + to, + content.content.map((node) => docToTreeNode(node.toJSON())), + ); + console.log( + `%c local: ${from}-${to}: ${JSON.stringify( + content.content, + )})`, + 'color: green', + ); } presence.set({ @@ -395,13 +423,24 @@

Yorkie.Tree

if (op.type !== 'tree-edit') { continue; } - const { from, to, value: contents } = op; + const { from, to, value: contents, splitLevel } = op; const transform = view.state.tr; - if (contents) { + if (splitLevel) { + view.selection; + transform.split(from, splitLevel); + console.log( + `%c remote: ${from}-${to}: split(${splitLevel})`, + 'color: skyblue', + ); + } else if (contents) { + console.log( + `%c remote: ${from}-${to}: ${JSON.stringify(contents)}`, + 'color: skyblue', + ); transform.replaceWith( from, to, - ...contents.map((content) => + Array.from(contents).map((content) => Node.fromJSON(mySchema, { type: content.type, text: content.value, @@ -409,6 +448,7 @@

Yorkie.Tree

), ); } else { + console.log(`%c remote: ${from}-${to}: delete`, 'color: skyblue'); transform.replace(from, to); } const newState = view.state.apply(transform); diff --git a/src/api/converter.ts b/src/api/converter.ts index b86a777ff..3ee828f1e 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -398,6 +398,8 @@ function toOperation(operation: Operation): PbOperation { pbTreeEditOperation.setContentsList( toTreeNodesWhenEdit(treeEditOperation.getContents()!), ); + pbTreeEditOperation.setSplitLevel(treeEditOperation.getSplitLevel()); + pbTreeEditOperation.setExecutedAt( toTimeTicket(treeEditOperation.getExecutedAt()), ); @@ -1125,8 +1127,9 @@ function fromOperations(pbOperations: Array): Array { fromTimeTicket(pbTreeEditOperation!.getParentCreatedAt())!, fromTreePos(pbTreeEditOperation!.getFrom()!), fromTreePos(pbTreeEditOperation!.getTo()!), - createdAtMapByActor, fromTreeNodesWhenEdit(pbTreeEditOperation!.getContentsList()), + pbTreeEditOperation!.getSplitLevel(), + createdAtMapByActor, fromTimeTicket(pbTreeEditOperation!.getExecutedAt())!, ); } else if (pbOperation.hasTreeStyle()) { diff --git a/src/api/yorkie/v1/resources.proto b/src/api/yorkie/v1/resources.proto index 75947b1df..ad27ca5c8 100644 --- a/src/api/yorkie/v1/resources.proto +++ b/src/api/yorkie/v1/resources.proto @@ -124,6 +124,7 @@ message Operation { TreePos to = 3; map created_at_map_by_actor = 4; repeated TreeNodes contents = 5; + int32 split_level = 7; TimeTicket executed_at = 6; } message TreeStyle { @@ -358,9 +359,16 @@ enum DocEventType { DOC_EVENT_TYPE_DOCUMENT_CHANGED = 0; DOC_EVENT_TYPE_DOCUMENT_WATCHED = 1; DOC_EVENT_TYPE_DOCUMENT_UNWATCHED = 2; + DOC_EVENT_TYPE_DOCUMENT_BROADCAST = 3; +} + +message DocEventBody { + string topic = 1; + bytes payload = 2; } message DocEvent { DocEventType type = 1; string publisher = 2; + DocEventBody body = 3; } diff --git a/src/api/yorkie/v1/resources_pb.d.ts b/src/api/yorkie/v1/resources_pb.d.ts index 3f1c314c7..c5f96d0fd 100644 --- a/src/api/yorkie/v1/resources_pb.d.ts +++ b/src/api/yorkie/v1/resources_pb.d.ts @@ -559,6 +559,9 @@ export namespace Operation { clearContentsList(): TreeEdit; addContents(value?: TreeNodes, index?: number): TreeNodes; + getSplitLevel(): number; + setSplitLevel(value: number): TreeEdit; + getExecutedAt(): TimeTicket | undefined; setExecutedAt(value?: TimeTicket): TreeEdit; hasExecutedAt(): boolean; @@ -579,6 +582,7 @@ export namespace Operation { to?: TreePos.AsObject, createdAtMapByActorMap: Array<[string, TimeTicket.AsObject]>, contentsList: Array, + splitLevel: number, executedAt?: TimeTicket.AsObject, } } @@ -1564,6 +1568,30 @@ export namespace TimeTicket { } } +export class DocEventBody extends jspb.Message { + getTopic(): string; + setTopic(value: string): DocEventBody; + + getPayload(): Uint8Array | string; + getPayload_asU8(): Uint8Array; + getPayload_asB64(): string; + setPayload(value: Uint8Array | string): DocEventBody; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): DocEventBody.AsObject; + static toObject(includeInstance: boolean, msg: DocEventBody): DocEventBody.AsObject; + static serializeBinaryToWriter(message: DocEventBody, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): DocEventBody; + static deserializeBinaryFromReader(message: DocEventBody, reader: jspb.BinaryReader): DocEventBody; +} + +export namespace DocEventBody { + export type AsObject = { + topic: string, + payload: Uint8Array | string, + } +} + export class DocEvent extends jspb.Message { getType(): DocEventType; setType(value: DocEventType): DocEvent; @@ -1571,6 +1599,11 @@ export class DocEvent extends jspb.Message { getPublisher(): string; setPublisher(value: string): DocEvent; + getBody(): DocEventBody | undefined; + setBody(value?: DocEventBody): DocEvent; + hasBody(): boolean; + clearBody(): DocEvent; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): DocEvent.AsObject; static toObject(includeInstance: boolean, msg: DocEvent): DocEvent.AsObject; @@ -1583,6 +1616,7 @@ export namespace DocEvent { export type AsObject = { type: DocEventType, publisher: string, + body?: DocEventBody.AsObject, } } @@ -1606,4 +1640,5 @@ export enum DocEventType { DOC_EVENT_TYPE_DOCUMENT_CHANGED = 0, DOC_EVENT_TYPE_DOCUMENT_WATCHED = 1, DOC_EVENT_TYPE_DOCUMENT_UNWATCHED = 2, + DOC_EVENT_TYPE_DOCUMENT_BROADCAST = 3, } diff --git a/src/api/yorkie/v1/resources_pb.js b/src/api/yorkie/v1/resources_pb.js index 841faa4fa..f97ef6105 100644 --- a/src/api/yorkie/v1/resources_pb.js +++ b/src/api/yorkie/v1/resources_pb.js @@ -13,7 +13,13 @@ var jspb = require('google-protobuf'); var goog = jspb; -var global = (function() { return this || window || global || self || Function('return this')(); }).call(null); +var global = + (typeof globalThis !== 'undefined' && globalThis) || + (typeof window !== 'undefined' && window) || + (typeof global !== 'undefined' && global) || + (typeof self !== 'undefined' && self) || + (function () { return this; }).call(null) || + Function('return this')(); var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js'); goog.object.extend(proto, google_protobuf_timestamp_pb); @@ -24,6 +30,7 @@ goog.exportSymbol('proto.yorkie.v1.ChangeID', null, global); goog.exportSymbol('proto.yorkie.v1.ChangePack', null, global); goog.exportSymbol('proto.yorkie.v1.Checkpoint', null, global); goog.exportSymbol('proto.yorkie.v1.DocEvent', null, global); +goog.exportSymbol('proto.yorkie.v1.DocEventBody', null, global); goog.exportSymbol('proto.yorkie.v1.DocEventType', null, global); goog.exportSymbol('proto.yorkie.v1.DocumentSummary', null, global); goog.exportSymbol('proto.yorkie.v1.JSONElement', null, global); @@ -949,6 +956,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.yorkie.v1.TimeTicket.displayName = 'proto.yorkie.v1.TimeTicket'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.yorkie.v1.DocEventBody = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.yorkie.v1.DocEventBody, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.yorkie.v1.DocEventBody.displayName = 'proto.yorkie.v1.DocEventBody'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -1151,7 +1179,8 @@ proto.yorkie.v1.Snapshot.prototype.getPresencesMap = function(opt_noLazyCreate) */ proto.yorkie.v1.Snapshot.prototype.clearPresencesMap = function() { this.getPresencesMap().clear(); - return this;}; + return this; +}; @@ -3804,7 +3833,8 @@ proto.yorkie.v1.Operation.Edit.prototype.getCreatedAtMapByActorMap = function(op */ proto.yorkie.v1.Operation.Edit.prototype.clearCreatedAtMapByActorMap = function() { this.getCreatedAtMapByActorMap().clear(); - return this;}; + return this; +}; /** @@ -3881,7 +3911,8 @@ proto.yorkie.v1.Operation.Edit.prototype.getAttributesMap = function(opt_noLazyC */ proto.yorkie.v1.Operation.Edit.prototype.clearAttributesMap = function() { this.getAttributesMap().clear(); - return this;}; + return this; +}; @@ -4496,7 +4527,8 @@ proto.yorkie.v1.Operation.Style.prototype.getAttributesMap = function(opt_noLazy */ proto.yorkie.v1.Operation.Style.prototype.clearAttributesMap = function() { this.getAttributesMap().clear(); - return this;}; + return this; +}; /** @@ -4555,7 +4587,8 @@ proto.yorkie.v1.Operation.Style.prototype.getCreatedAtMapByActorMap = function(o */ proto.yorkie.v1.Operation.Style.prototype.clearCreatedAtMapByActorMap = function() { this.getCreatedAtMapByActorMap().clear(); - return this;}; + return this; +}; @@ -4856,6 +4889,7 @@ proto.yorkie.v1.Operation.TreeEdit.toObject = function(includeInstance, msg) { createdAtMapByActorMap: (f = msg.getCreatedAtMapByActorMap()) ? f.toObject(includeInstance, proto.yorkie.v1.TimeTicket.toObject) : [], contentsList: jspb.Message.toObjectList(msg.getContentsList(), proto.yorkie.v1.TreeNodes.toObject, includeInstance), + splitLevel: jspb.Message.getFieldWithDefault(msg, 7, 0), executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) }; @@ -4919,6 +4953,10 @@ proto.yorkie.v1.Operation.TreeEdit.deserializeBinaryFromReader = function(msg, r reader.readMessage(value,proto.yorkie.v1.TreeNodes.deserializeBinaryFromReader); msg.addContents(value); break; + case 7: + var value = /** @type {number} */ (reader.readInt32()); + msg.setSplitLevel(value); + break; case 6: var value = new proto.yorkie.v1.TimeTicket; reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); @@ -4989,6 +5027,13 @@ proto.yorkie.v1.Operation.TreeEdit.serializeBinaryToWriter = function(message, w proto.yorkie.v1.TreeNodes.serializeBinaryToWriter ); } + f = message.getSplitLevel(); + if (f !== 0) { + writer.writeInt32( + 7, + f + ); + } f = message.getExecutedAt(); if (f != null) { writer.writeMessage( @@ -5130,7 +5175,8 @@ proto.yorkie.v1.Operation.TreeEdit.prototype.getCreatedAtMapByActorMap = functio */ proto.yorkie.v1.Operation.TreeEdit.prototype.clearCreatedAtMapByActorMap = function() { this.getCreatedAtMapByActorMap().clear(); - return this;}; + return this; +}; /** @@ -5171,6 +5217,24 @@ proto.yorkie.v1.Operation.TreeEdit.prototype.clearContentsList = function() { }; +/** + * optional int32 split_level = 7; + * @return {number} + */ +proto.yorkie.v1.Operation.TreeEdit.prototype.getSplitLevel = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this + */ +proto.yorkie.v1.Operation.TreeEdit.prototype.setSplitLevel = function(value) { + return jspb.Message.setProto3IntField(this, 7, value); +}; + + /** * optional TimeTicket executed_at = 6; * @return {?proto.yorkie.v1.TimeTicket} @@ -5505,7 +5569,8 @@ proto.yorkie.v1.Operation.TreeStyle.prototype.getAttributesMap = function(opt_no */ proto.yorkie.v1.Operation.TreeStyle.prototype.clearAttributesMap = function() { this.getAttributesMap().clear(); - return this;}; + return this; +}; /** @@ -9491,7 +9556,8 @@ proto.yorkie.v1.TextNode.prototype.getAttributesMap = function(opt_noLazyCreate) */ proto.yorkie.v1.TextNode.prototype.clearAttributesMap = function() { this.getAttributesMap().clear(); - return this;}; + return this; +}; @@ -10099,7 +10165,8 @@ proto.yorkie.v1.TreeNode.prototype.getAttributesMap = function(opt_noLazyCreate) */ proto.yorkie.v1.TreeNode.prototype.clearAttributesMap = function() { this.getAttributesMap().clear(); - return this;}; + return this; +}; @@ -12418,7 +12485,8 @@ proto.yorkie.v1.Presence.prototype.getDataMap = function(opt_noLazyCreate) { */ proto.yorkie.v1.Presence.prototype.clearDataMap = function() { this.getDataMap().clear(); - return this;}; + return this; +}; @@ -13009,6 +13077,190 @@ proto.yorkie.v1.TimeTicket.prototype.setActorId = function(value) { +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.yorkie.v1.DocEventBody.prototype.toObject = function(opt_includeInstance) { + return proto.yorkie.v1.DocEventBody.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.yorkie.v1.DocEventBody} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.DocEventBody.toObject = function(includeInstance, msg) { + var f, obj = { + topic: jspb.Message.getFieldWithDefault(msg, 1, ""), + payload: msg.getPayload_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.yorkie.v1.DocEventBody} + */ +proto.yorkie.v1.DocEventBody.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.yorkie.v1.DocEventBody; + return proto.yorkie.v1.DocEventBody.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.yorkie.v1.DocEventBody} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.yorkie.v1.DocEventBody} + */ +proto.yorkie.v1.DocEventBody.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setTopic(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPayload(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.yorkie.v1.DocEventBody.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.yorkie.v1.DocEventBody.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.yorkie.v1.DocEventBody} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.DocEventBody.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getTopic(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getPayload_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional string topic = 1; + * @return {string} + */ +proto.yorkie.v1.DocEventBody.prototype.getTopic = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.yorkie.v1.DocEventBody} returns this + */ +proto.yorkie.v1.DocEventBody.prototype.setTopic = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional bytes payload = 2; + * @return {string} + */ +proto.yorkie.v1.DocEventBody.prototype.getPayload = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes payload = 2; + * This is a type-conversion wrapper around `getPayload()` + * @return {string} + */ +proto.yorkie.v1.DocEventBody.prototype.getPayload_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPayload())); +}; + + +/** + * optional bytes payload = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPayload()` + * @return {!Uint8Array} + */ +proto.yorkie.v1.DocEventBody.prototype.getPayload_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPayload())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.yorkie.v1.DocEventBody} returns this + */ +proto.yorkie.v1.DocEventBody.prototype.setPayload = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + + + + if (jspb.Message.GENERATE_TO_OBJECT) { /** * Creates an object representation of this proto. @@ -13039,7 +13291,8 @@ proto.yorkie.v1.DocEvent.prototype.toObject = function(opt_includeInstance) { proto.yorkie.v1.DocEvent.toObject = function(includeInstance, msg) { var f, obj = { type: jspb.Message.getFieldWithDefault(msg, 1, 0), - publisher: jspb.Message.getFieldWithDefault(msg, 2, "") + publisher: jspb.Message.getFieldWithDefault(msg, 2, ""), + body: (f = msg.getBody()) && proto.yorkie.v1.DocEventBody.toObject(includeInstance, f) }; if (includeInstance) { @@ -13084,6 +13337,11 @@ proto.yorkie.v1.DocEvent.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {string} */ (reader.readString()); msg.setPublisher(value); break; + case 3: + var value = new proto.yorkie.v1.DocEventBody; + reader.readMessage(value,proto.yorkie.v1.DocEventBody.deserializeBinaryFromReader); + msg.setBody(value); + break; default: reader.skipField(); break; @@ -13127,6 +13385,14 @@ proto.yorkie.v1.DocEvent.serializeBinaryToWriter = function(message, writer) { f ); } + f = message.getBody(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.yorkie.v1.DocEventBody.serializeBinaryToWriter + ); + } }; @@ -13166,6 +13432,43 @@ proto.yorkie.v1.DocEvent.prototype.setPublisher = function(value) { }; +/** + * optional DocEventBody body = 3; + * @return {?proto.yorkie.v1.DocEventBody} + */ +proto.yorkie.v1.DocEvent.prototype.getBody = function() { + return /** @type{?proto.yorkie.v1.DocEventBody} */ ( + jspb.Message.getWrapperField(this, proto.yorkie.v1.DocEventBody, 3)); +}; + + +/** + * @param {?proto.yorkie.v1.DocEventBody|undefined} value + * @return {!proto.yorkie.v1.DocEvent} returns this +*/ +proto.yorkie.v1.DocEvent.prototype.setBody = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.yorkie.v1.DocEvent} returns this + */ +proto.yorkie.v1.DocEvent.prototype.clearBody = function() { + return this.setBody(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.yorkie.v1.DocEvent.prototype.hasBody = function() { + return jspb.Message.getField(this, 3) != null; +}; + + /** * @enum {number} */ @@ -13192,7 +13495,8 @@ proto.yorkie.v1.ValueType = { proto.yorkie.v1.DocEventType = { DOC_EVENT_TYPE_DOCUMENT_CHANGED: 0, DOC_EVENT_TYPE_DOCUMENT_WATCHED: 1, - DOC_EVENT_TYPE_DOCUMENT_UNWATCHED: 2 + DOC_EVENT_TYPE_DOCUMENT_UNWATCHED: 2, + DOC_EVENT_TYPE_DOCUMENT_BROADCAST: 3 }; goog.object.extend(exports, proto.yorkie.v1); diff --git a/src/api/yorkie/v1/yorkie.proto b/src/api/yorkie/v1/yorkie.proto index 639ddd37d..da71d6a11 100644 --- a/src/api/yorkie/v1/yorkie.proto +++ b/src/api/yorkie/v1/yorkie.proto @@ -35,6 +35,8 @@ service YorkieService { rpc PushPullChanges (PushPullChangesRequest) returns (PushPullChangesResponse) {} rpc WatchDocument (WatchDocumentRequest) returns (stream WatchDocumentResponse) {} + + rpc Broadcast (BroadcastRequest) returns (BroadcastResponse) {} } message ActivateClientRequest { @@ -109,3 +111,13 @@ message PushPullChangesRequest { message PushPullChangesResponse { ChangePack change_pack = 1; } + +message BroadcastRequest { + string client_id = 1; + string document_id = 2; + string topic = 3; + bytes payload = 4; +} + +message BroadcastResponse { +} diff --git a/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts b/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts index 20f60c90c..11089c8da 100644 --- a/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts +++ b/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts @@ -55,6 +55,13 @@ export class YorkieServiceClient { metadata?: grpcWeb.Metadata ): grpcWeb.ClientReadableStream; + broadcast( + request: yorkie_v1_yorkie_pb.BroadcastRequest, + metadata: grpcWeb.Metadata | undefined, + callback: (err: grpcWeb.RpcError, + response: yorkie_v1_yorkie_pb.BroadcastResponse) => void + ): grpcWeb.ClientReadableStream; + } export class YorkieServicePromiseClient { @@ -97,5 +104,10 @@ export class YorkieServicePromiseClient { metadata?: grpcWeb.Metadata ): grpcWeb.ClientReadableStream; + broadcast( + request: yorkie_v1_yorkie_pb.BroadcastRequest, + metadata?: grpcWeb.Metadata + ): Promise; + } diff --git a/src/api/yorkie/v1/yorkie_grpc_web_pb.js b/src/api/yorkie/v1/yorkie_grpc_web_pb.js index ff8f94ad1..89725d283 100644 --- a/src/api/yorkie/v1/yorkie_grpc_web_pb.js +++ b/src/api/yorkie/v1/yorkie_grpc_web_pb.js @@ -7,7 +7,7 @@ // Code generated by protoc-gen-grpc-web. DO NOT EDIT. // versions: // protoc-gen-grpc-web v1.4.2 -// protoc v3.20.3 +// protoc v4.24.4 // source: yorkie/v1/yorkie.proto @@ -499,5 +499,66 @@ proto.yorkie.v1.YorkieServicePromiseClient.prototype.watchDocument = }; +/** + * @const + * @type {!grpc.web.MethodDescriptor< + * !proto.yorkie.v1.BroadcastRequest, + * !proto.yorkie.v1.BroadcastResponse>} + */ +const methodDescriptor_YorkieService_Broadcast = new grpc.web.MethodDescriptor( + '/yorkie.v1.YorkieService/Broadcast', + grpc.web.MethodType.UNARY, + proto.yorkie.v1.BroadcastRequest, + proto.yorkie.v1.BroadcastResponse, + /** + * @param {!proto.yorkie.v1.BroadcastRequest} request + * @return {!Uint8Array} + */ + function(request) { + return request.serializeBinary(); + }, + proto.yorkie.v1.BroadcastResponse.deserializeBinary +); + + +/** + * @param {!proto.yorkie.v1.BroadcastRequest} request The + * request proto + * @param {?Object} metadata User defined + * call metadata + * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.BroadcastResponse)} + * callback The callback function(error, response) + * @return {!grpc.web.ClientReadableStream|undefined} + * The XHR Node Readable Stream + */ +proto.yorkie.v1.YorkieServiceClient.prototype.broadcast = + function(request, metadata, callback) { + return this.client_.rpcCall(this.hostname_ + + '/yorkie.v1.YorkieService/Broadcast', + request, + metadata || {}, + methodDescriptor_YorkieService_Broadcast, + callback); +}; + + +/** + * @param {!proto.yorkie.v1.BroadcastRequest} request The + * request proto + * @param {?Object=} metadata User defined + * call metadata + * @return {!Promise} + * Promise that resolves to the response + */ +proto.yorkie.v1.YorkieServicePromiseClient.prototype.broadcast = + function(request, metadata) { + return this.client_.unaryCall(this.hostname_ + + '/yorkie.v1.YorkieService/Broadcast', + request, + metadata || {}, + methodDescriptor_YorkieService_Broadcast); +}; + + module.exports = proto.yorkie.v1; diff --git a/src/api/yorkie/v1/yorkie_pb.d.ts b/src/api/yorkie/v1/yorkie_pb.d.ts index 7038d71de..0a3992403 100644 --- a/src/api/yorkie/v1/yorkie_pb.d.ts +++ b/src/api/yorkie/v1/yorkie_pb.d.ts @@ -348,3 +348,49 @@ export namespace PushPullChangesResponse { } } +export class BroadcastRequest extends jspb.Message { + getClientId(): string; + setClientId(value: string): BroadcastRequest; + + getDocumentId(): string; + setDocumentId(value: string): BroadcastRequest; + + getTopic(): string; + setTopic(value: string): BroadcastRequest; + + getPayload(): Uint8Array | string; + getPayload_asU8(): Uint8Array; + getPayload_asB64(): string; + setPayload(value: Uint8Array | string): BroadcastRequest; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): BroadcastRequest.AsObject; + static toObject(includeInstance: boolean, msg: BroadcastRequest): BroadcastRequest.AsObject; + static serializeBinaryToWriter(message: BroadcastRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): BroadcastRequest; + static deserializeBinaryFromReader(message: BroadcastRequest, reader: jspb.BinaryReader): BroadcastRequest; +} + +export namespace BroadcastRequest { + export type AsObject = { + clientId: string, + documentId: string, + topic: string, + payload: Uint8Array | string, + } +} + +export class BroadcastResponse extends jspb.Message { + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): BroadcastResponse.AsObject; + static toObject(includeInstance: boolean, msg: BroadcastResponse): BroadcastResponse.AsObject; + static serializeBinaryToWriter(message: BroadcastResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): BroadcastResponse; + static deserializeBinaryFromReader(message: BroadcastResponse, reader: jspb.BinaryReader): BroadcastResponse; +} + +export namespace BroadcastResponse { + export type AsObject = { + } +} + diff --git a/src/api/yorkie/v1/yorkie_pb.js b/src/api/yorkie/v1/yorkie_pb.js index ab01e8d1f..553b34687 100644 --- a/src/api/yorkie/v1/yorkie_pb.js +++ b/src/api/yorkie/v1/yorkie_pb.js @@ -13,7 +13,13 @@ var jspb = require('google-protobuf'); var goog = jspb; -var global = (function() { return this || window || global || self || Function('return this')(); }).call(null); +var global = + (typeof globalThis !== 'undefined' && globalThis) || + (typeof window !== 'undefined' && window) || + (typeof global !== 'undefined' && global) || + (typeof self !== 'undefined' && self) || + (function () { return this; }).call(null) || + Function('return this')(); var yorkie_v1_resources_pb = require('../../yorkie/v1/resources_pb.js'); goog.object.extend(proto, yorkie_v1_resources_pb); @@ -21,6 +27,8 @@ goog.exportSymbol('proto.yorkie.v1.ActivateClientRequest', null, global); goog.exportSymbol('proto.yorkie.v1.ActivateClientResponse', null, global); goog.exportSymbol('proto.yorkie.v1.AttachDocumentRequest', null, global); goog.exportSymbol('proto.yorkie.v1.AttachDocumentResponse', null, global); +goog.exportSymbol('proto.yorkie.v1.BroadcastRequest', null, global); +goog.exportSymbol('proto.yorkie.v1.BroadcastResponse', null, global); goog.exportSymbol('proto.yorkie.v1.DeactivateClientRequest', null, global); goog.exportSymbol('proto.yorkie.v1.DeactivateClientResponse', null, global); goog.exportSymbol('proto.yorkie.v1.DetachDocumentRequest', null, global); @@ -348,6 +356,48 @@ if (goog.DEBUG && !COMPILED) { */ proto.yorkie.v1.PushPullChangesResponse.displayName = 'proto.yorkie.v1.PushPullChangesResponse'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.yorkie.v1.BroadcastRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.yorkie.v1.BroadcastRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.yorkie.v1.BroadcastRequest.displayName = 'proto.yorkie.v1.BroadcastRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.yorkie.v1.BroadcastResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.yorkie.v1.BroadcastResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.yorkie.v1.BroadcastResponse.displayName = 'proto.yorkie.v1.BroadcastResponse'; +} @@ -2891,4 +2941,349 @@ proto.yorkie.v1.PushPullChangesResponse.prototype.hasChangePack = function() { }; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.yorkie.v1.BroadcastRequest.prototype.toObject = function(opt_includeInstance) { + return proto.yorkie.v1.BroadcastRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.yorkie.v1.BroadcastRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.BroadcastRequest.toObject = function(includeInstance, msg) { + var f, obj = { + clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), + documentId: jspb.Message.getFieldWithDefault(msg, 2, ""), + topic: jspb.Message.getFieldWithDefault(msg, 3, ""), + payload: msg.getPayload_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.yorkie.v1.BroadcastRequest} + */ +proto.yorkie.v1.BroadcastRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.yorkie.v1.BroadcastRequest; + return proto.yorkie.v1.BroadcastRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.yorkie.v1.BroadcastRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.yorkie.v1.BroadcastRequest} + */ +proto.yorkie.v1.BroadcastRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setClientId(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setDocumentId(value); + break; + case 3: + var value = /** @type {string} */ (reader.readString()); + msg.setTopic(value); + break; + case 4: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPayload(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.yorkie.v1.BroadcastRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.yorkie.v1.BroadcastRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.yorkie.v1.BroadcastRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.BroadcastRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getClientId(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getDocumentId(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getTopic(); + if (f.length > 0) { + writer.writeString( + 3, + f + ); + } + f = message.getPayload_asU8(); + if (f.length > 0) { + writer.writeBytes( + 4, + f + ); + } +}; + + +/** + * optional string client_id = 1; + * @return {string} + */ +proto.yorkie.v1.BroadcastRequest.prototype.getClientId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.yorkie.v1.BroadcastRequest} returns this + */ +proto.yorkie.v1.BroadcastRequest.prototype.setClientId = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional string document_id = 2; + * @return {string} + */ +proto.yorkie.v1.BroadcastRequest.prototype.getDocumentId = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.yorkie.v1.BroadcastRequest} returns this + */ +proto.yorkie.v1.BroadcastRequest.prototype.setDocumentId = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional string topic = 3; + * @return {string} + */ +proto.yorkie.v1.BroadcastRequest.prototype.getTopic = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * @param {string} value + * @return {!proto.yorkie.v1.BroadcastRequest} returns this + */ +proto.yorkie.v1.BroadcastRequest.prototype.setTopic = function(value) { + return jspb.Message.setProto3StringField(this, 3, value); +}; + + +/** + * optional bytes payload = 4; + * @return {string} + */ +proto.yorkie.v1.BroadcastRequest.prototype.getPayload = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); +}; + + +/** + * optional bytes payload = 4; + * This is a type-conversion wrapper around `getPayload()` + * @return {string} + */ +proto.yorkie.v1.BroadcastRequest.prototype.getPayload_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPayload())); +}; + + +/** + * optional bytes payload = 4; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPayload()` + * @return {!Uint8Array} + */ +proto.yorkie.v1.BroadcastRequest.prototype.getPayload_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPayload())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.yorkie.v1.BroadcastRequest} returns this + */ +proto.yorkie.v1.BroadcastRequest.prototype.setPayload = function(value) { + return jspb.Message.setProto3BytesField(this, 4, value); +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.yorkie.v1.BroadcastResponse.prototype.toObject = function(opt_includeInstance) { + return proto.yorkie.v1.BroadcastResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.yorkie.v1.BroadcastResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.BroadcastResponse.toObject = function(includeInstance, msg) { + var f, obj = { + + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.yorkie.v1.BroadcastResponse} + */ +proto.yorkie.v1.BroadcastResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.yorkie.v1.BroadcastResponse; + return proto.yorkie.v1.BroadcastResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.yorkie.v1.BroadcastResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.yorkie.v1.BroadcastResponse} + */ +proto.yorkie.v1.BroadcastResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.yorkie.v1.BroadcastResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.yorkie.v1.BroadcastResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.yorkie.v1.BroadcastResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.yorkie.v1.BroadcastResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; +}; + + goog.object.extend(exports, proto.yorkie.v1); diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index 41230f3e9..4c26067e4 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -91,6 +91,7 @@ export interface TreeChange { fromPath: Array; toPath: Array; value?: Array | { [key: string]: any }; + splitLevel?: number; } /** @@ -121,30 +122,27 @@ export class CRDTTreePos { public static fromTreePos(pos: TreePos): CRDTTreePos { const { offset } = pos; let { node } = pos; - let leftSibling; + let leftNode; if (node.isText) { if (node.parent!.children[0] === node && offset === 0) { - leftSibling = node.parent!; + leftNode = node.parent!; } else { - leftSibling = node; + leftNode = node; } node = node.parent!; } else { if (offset === 0) { - leftSibling = node; + leftNode = node; } else { - leftSibling = node.children[offset - 1]; + leftNode = node.children[offset - 1]; } } return CRDTTreePos.of( node.id, - CRDTTreeNodeID.of( - leftSibling.getCreatedAt(), - leftSibling.getOffset() + offset, - ), + CRDTTreeNodeID.of(leftNode.getCreatedAt(), leftNode.getOffset() + offset), ); } @@ -189,6 +187,9 @@ export class CRDTTreePos { /** * `toTreeNodes` converts the pos to parent and left sibling nodes. + * If the position points to the middle of a node, then the left sibling node + * is the node that contains the position. Otherwise, the left sibling node is + * the node that is located at the left of the position. */ public toTreeNodes(tree: CRDTTree): [CRDTTreeNode, CRDTTreeNode] { const parentID = this.getParentID(); @@ -199,15 +200,21 @@ export class CRDTTreePos { throw new Error(`cannot find node at ${this}`); } + /** + * NOTE(hackerwins): If the left node and the parent node are the same, + * it means that the position is the left-most of the parent node. + * We need to skip finding the left of the position. + */ if ( + !leftSiblingID.equals(parentID) && leftSiblingID.getOffset() > 0 && leftSiblingID.getOffset() === leftNode.id.getOffset() && leftNode.insPrevID ) { - leftNode = tree.findFloorNode(leftNode.insPrevID) || leftNode; + leftNode = tree.findFloorNode(leftNode.insPrevID)!; } - return [parentNode, leftNode!]; + return [parentNode, leftNode]; } /** @@ -499,6 +506,27 @@ export class CRDTTreeNode extends IndexTreeNode { ); } + /** + * `split` splits the given offset of this node. + */ + public split(tree: CRDTTree, offset: number): CRDTTreeNode | undefined { + const split = this.isText + ? this.splitText(offset, this.id.getOffset()) + : this.splitElement(offset, this.id.getOffset()); + + if (split) { + split.insPrevID = this.id; + if (this.insNextID) { + const insNext = tree.findFloorNode(this.insNextID)!; + insNext.insPrevID = split.id; + split.insNextID = this.insNextID; + } + this.insNextID = split.id; + tree.registerNode(split); + } + return split; + } + /** * `getCreatedAt` returns the creation time of this element. */ @@ -620,14 +648,21 @@ export class CRDTTree extends CRDTGCElement { } /** - * `findNodesAndSplit` finds `TreePos` of the given `CRDTTreeNodeID` and - * splits nodes for the given split level. + * `registerNode` registers the given node to the tree. + */ + public registerNode(node: CRDTTreeNode): void { + this.nodeMapByID.put(node.id, node); + } + + /** + * `findNodesAndSplitText` finds `TreePos` of the given `CRDTTreeNodeID` and + * splits nodes if the position is in the middle of a text node. * * The ids of the given `pos` are the ids of the node in the CRDT perspective. * This is different from `TreePos` which is a position of the tree in the * physical perspective. */ - public findNodesAndSplit( + public findNodesAndSplitText( pos: CRDTTreePos, editedAt: TimeTicket, ): [CRDTTreeNode, CRDTTreeNode] { @@ -635,25 +670,12 @@ export class CRDTTree extends CRDTGCElement { const [parent, leftSibling] = pos.toTreeNodes(this); let leftNode = leftSibling; - // 02. Split nodes for the given split level. + // 02. Split text node if the left node is a text node. if (leftNode.isText) { - const absOffset = leftNode.id.getOffset(); - const split = leftNode.split( - pos.getLeftSiblingID().getOffset() - absOffset, - absOffset, + leftNode.split( + this, + pos.getLeftSiblingID().getOffset() - leftNode.id.getOffset(), ); - - if (split) { - split.insPrevID = leftNode.id; - if (leftNode.insNextID) { - const insNext = this.findFloorNode(leftNode.insNextID)!; - insNext.insPrevID = split.id; - split.insNextID = leftNode.insNextID; - } - leftNode.insNextID = split.id; - - this.nodeMapByID.put(split.id, split); - } } // 03. Find the appropriate left node. If some nodes are inserted at the @@ -682,8 +704,11 @@ export class CRDTTree extends CRDTGCElement { attributes: { [key: string]: string } | undefined, editedAt: TimeTicket, ) { - const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], editedAt); - const [toParent, toLeft] = this.findNodesAndSplit(range[1], editedAt); + const [fromParent, fromLeft] = this.findNodesAndSplitText( + range[0], + editedAt, + ); + const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); const changes: Array = []; changes.push({ type: TreeChangeType.Style, @@ -717,32 +742,20 @@ export class CRDTTree extends CRDTGCElement { public edit( range: [CRDTTreePos, CRDTTreePos], contents: Array | undefined, + splitLevel: number, editedAt: TimeTicket, latestCreatedAtMapByActor?: Map, ): [Array, Map] { - // 01. split text nodes at the given range if needed. - const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], editedAt); - const [toParent, toLeft] = this.findNodesAndSplit(range[1], editedAt); - - // TODO(hackerwins): If concurrent deletion happens, we need to seperate the - // range(from, to) into multiple ranges. - const changes: Array = []; - changes.push({ - type: TreeChangeType.Content, - from: this.toIndex(fromParent, fromLeft), - to: this.toIndex(toParent, toLeft), - fromPath: this.toPath(fromParent, fromLeft), - toPath: this.toPath(toParent, toLeft), - actor: editedAt.getActorID()!, - value: contents?.length - ? contents.map((content) => toTreeNode(content)) - : undefined, - }); + // 01. find nodes from the given range and split nodes. + const [fromParent, fromLeft] = this.findNodesAndSplitText( + range[0], + editedAt, + ); + const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); const toBeRemoveds: Array = []; const toBeMovedToFromParents: Array = []; const latestCreatedAtMap = new Map(); - this.traverseInPosRange( fromParent, fromLeft, @@ -762,9 +775,9 @@ export class CRDTTree extends CRDTGCElement { // between two parents. For now, we only merge two parents are // both element nodes having text children. // e.g.

a|b

c|d

->

a|d

- if (!fromParent.hasTextChild() || !toParent.hasTextChild()) { - return; - } + // if (!fromParent.hasTextChild() || !toParent.hasTextChild()) { + // return; + // } for (const child of node.children) { if (toBeRemoveds.includes(child)) { @@ -795,6 +808,23 @@ export class CRDTTree extends CRDTGCElement { }, ); + // TODO(hackerwins): If concurrent deletion happens, we need to seperate the + // range(from, to) into multiple ranges. + const changes: Array = []; + changes.push({ + type: TreeChangeType.Content, + from: this.toIndex(fromParent, fromLeft), + to: this.toIndex(toParent, toLeft), + fromPath: this.toPath(fromParent, fromLeft), + toPath: this.toPath(toParent, toLeft), + actor: editedAt.getActorID()!, + value: contents?.length + ? contents.map((content) => toTreeNode(content)) + : undefined, + splitLevel, + }); + + // 02. Delete: delete the nodes that are marked as removed. for (const node of toBeRemoveds) { node.remove(editedAt); if (node.isRemoved) { @@ -802,31 +832,44 @@ export class CRDTTree extends CRDTGCElement { } } + // 03. Merge: move the nodes that are marked as moved. for (const node of toBeMovedToFromParents) { fromParent.append(node); } - // 03. insert the given node at the given position. + // 04. Split: split the element nodes for the given split level. + if (splitLevel > 0) { + let splitCount = 0; + let parent = fromParent; + let left = fromLeft; + while (splitCount < splitLevel) { + parent.split(this, parent.findOffset(left) + 1); + left = parent; + parent = parent.parent!; + splitCount++; + } + } + + // 05. Insert: insert the given nodes at the given position. if (contents?.length) { let leftInChildren = fromLeft; // tree - for (const content of contents!) { - // 03-1. insert the content nodes to the tree. + for (const content of contents) { + // 05-1. Insert the content nodes to the tree. if (leftInChildren === fromParent) { - // 03-1-1. when there's no leftSibling, then insert content into very front of parent's children List + // 05-1-1. when there's no leftSibling, then insert content into very front of parent's children. fromParent.insertAt(content, 0); } else { - // 03-1-2. insert after leftSibling + // 05-1-2. insert after leftSibling fromParent.insertAfter(content, leftInChildren); } leftInChildren = content; traverseAll(content, (node) => { - // if insertion happens during concurrent editing and parent node has been removed, - // make new nodes as tombstone immediately + // If insertion happens during concurrent editing and parent node has been removed, + // make new nodes as tombstone immediately. if (fromParent.isRemoved) { node.remove(editedAt); - this.removedNodeMap.set(node.id.toIDString(), node); } @@ -845,11 +888,12 @@ export class CRDTTree extends CRDTGCElement { public editT( range: [number, number], contents: Array | undefined, + splitLevel: number, editedAt: TimeTicket, ): void { const fromPos = this.findPos(range[0]); const toPos = this.findPos(range[1]); - this.edit([fromPos, toPos], contents, editedAt); + this.edit([fromPos, toPos], contents, splitLevel, editedAt); } /** @@ -1020,9 +1064,9 @@ export class CRDTTree extends CRDTGCElement { */ public toPath( parentNode: CRDTTreeNode, - leftSiblingNode: CRDTTreeNode, + leftNode: CRDTTreeNode, ): Array { - const treePos = this.toTreePos(parentNode, leftSiblingNode); + const treePos = this.toTreePos(parentNode, leftNode); if (!treePos) { return []; } @@ -1033,11 +1077,8 @@ export class CRDTTree extends CRDTGCElement { /** * `toIndex` converts the given CRDTTreeNodeID to the index of the tree. */ - public toIndex( - parentNode: CRDTTreeNode, - leftSiblingNode: CRDTTreeNode, - ): number { - const treePos = this.toTreePos(parentNode, leftSiblingNode); + public toIndex(parentNode: CRDTTreeNode, leftNode: CRDTTreeNode): number { + const treePos = this.toTreePos(parentNode, leftNode); if (!treePos) { return -1; } @@ -1092,8 +1133,11 @@ export class CRDTTree extends CRDTGCElement { range: TreePosRange, timeTicket: TimeTicket, ): [Array, Array] { - const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], timeTicket); - const [toParent, toLeft] = this.findNodesAndSplit(range[1], timeTicket); + const [fromParent, fromLeft] = this.findNodesAndSplitText( + range[0], + timeTicket, + ); + const [toParent, toLeft] = this.findNodesAndSplitText(range[1], timeTicket); return [this.toPath(fromParent, fromLeft), this.toPath(toParent, toLeft)]; } @@ -1104,8 +1148,11 @@ export class CRDTTree extends CRDTGCElement { range: TreePosRange, timeTicket: TimeTicket, ): [number, number] { - const [fromParent, fromLeft] = this.findNodesAndSplit(range[0], timeTicket); - const [toParent, toLeft] = this.findNodesAndSplit(range[1], timeTicket); + const [fromParent, fromLeft] = this.findNodesAndSplitText( + range[0], + timeTicket, + ); + const [toParent, toLeft] = this.findNodesAndSplitText(range[1], timeTicket); return [this.toIndex(fromParent, fromLeft), this.toIndex(toParent, toLeft)]; } @@ -1129,9 +1176,9 @@ export class CRDTTree extends CRDTGCElement { */ private toTreePos( parentNode: CRDTTreeNode, - leftSiblingNode: CRDTTreeNode, + leftNode: CRDTTreeNode, ): TreePos | undefined { - if (!parentNode || !leftSiblingNode) { + if (!parentNode || !leftNode) { return; } @@ -1149,19 +1196,19 @@ export class CRDTTree extends CRDTGCElement { }; } - if (parentNode === leftSiblingNode) { + if (parentNode === leftNode) { return { node: parentNode, offset: 0, }; } - let offset = parentNode.findOffset(leftSiblingNode); - if (!leftSiblingNode.isRemoved) { - if (leftSiblingNode.isText) { + let offset = parentNode.findOffset(leftNode); + if (!leftNode.isRemoved) { + if (leftNode.isText) { return { - node: leftSiblingNode, - offset: leftSiblingNode.paddedSize, + node: leftNode, + offset: leftNode.paddedSize, }; } diff --git a/src/document/json/tree.ts b/src/document/json/tree.ts index 22c4bc022..a0a000a95 100644 --- a/src/document/json/tree.ts +++ b/src/document/json/tree.ts @@ -329,6 +329,7 @@ export class Tree { fromPos: CRDTTreePos, toPos: CRDTTreePos, contents: Array, + splitLevel = 0, ): boolean { if (contents.length !== 0 && contents[0]) { validateTreeNodes(contents); @@ -362,12 +363,12 @@ export class Tree { .filter((a) => a) as Array; } - // TODO(hackerwins): Implement splitLevels. const [, maxCreatedAtMapByActor] = this.tree!.edit( [fromPos, toPos], crdtNodes.length ? crdtNodes.map((crdtNode) => crdtNode?.deepcopy()) : undefined, + splitLevel, ticket, ); @@ -376,8 +377,9 @@ export class Tree { this.tree!.getCreatedAt(), fromPos, toPos, - maxCreatedAtMapByActor, crdtNodes.length ? crdtNodes : undefined, + splitLevel, + maxCreatedAtMapByActor, ticket, ), ); @@ -395,7 +397,8 @@ export class Tree { public editByPath( fromPath: Array, toPath: Array, - ...contents: Array + content?: TreeNode, + splitLevel = 0, ): boolean { if (!this.context || !this.tree) { throw new Error('it is not initialized yet'); @@ -410,7 +413,37 @@ export class Tree { const fromPos = this.tree.pathToPos(fromPath); const toPos = this.tree.pathToPos(toPath); - return this.editInternal(fromPos, toPos, contents); + return this.editInternal( + fromPos, + toPos, + content ? [content] : [], + splitLevel, + ); + } + + /** + * `editBulkByPath` edits this tree with the given node and path. + */ + public editBulkByPath( + fromPath: Array, + toPath: Array, + contents: Array, + splitLevel = 0, + ): boolean { + if (!this.context || !this.tree) { + throw new Error('it is not initialized yet'); + } + if (fromPath.length !== toPath.length) { + throw new Error('path length should be equal'); + } + if (!fromPath.length || !toPath.length) { + throw new Error('path should not be empty'); + } + + const fromPos = this.tree.pathToPos(fromPath); + const toPos = this.tree.pathToPos(toPath); + + return this.editInternal(fromPos, toPos, contents, splitLevel); } /** @@ -419,7 +452,35 @@ export class Tree { public edit( fromIdx: number, toIdx: number, - ...contents: Array + content?: TreeNode, + splitLevel = 0, + ): boolean { + if (!this.context || !this.tree) { + throw new Error('it is not initialized yet'); + } + if (fromIdx > toIdx) { + throw new Error('from should be less than or equal to to'); + } + + const fromPos = this.tree.findPos(fromIdx); + const toPos = this.tree.findPos(toIdx); + + return this.editInternal( + fromPos, + toPos, + content ? [content] : [], + splitLevel, + ); + } + + /** + * `editBulk` edits this tree with the given nodes. + */ + public editBulk( + fromIdx: number, + toIdx: number, + contents: Array, + splitLevel = 0, ): boolean { if (!this.context || !this.tree) { throw new Error('it is not initialized yet'); @@ -431,7 +492,7 @@ export class Tree { const fromPos = this.tree.findPos(fromIdx); const toPos = this.tree.findPos(toIdx); - return this.editInternal(fromPos, toPos, contents); + return this.editInternal(fromPos, toPos, contents, splitLevel); } /** diff --git a/src/document/operation/operation.ts b/src/document/operation/operation.ts index 3b246645b..e117397b9 100644 --- a/src/document/operation/operation.ts +++ b/src/document/operation/operation.ts @@ -119,9 +119,9 @@ export type IncreaseOpInfo = { */ export type EditOpInfo = { type: 'edit'; + path: string; from: number; to: number; - path: string; value: { attributes: Indexable; content: string; @@ -133,9 +133,9 @@ export type EditOpInfo = { */ export type StyleOpInfo = { type: 'style'; + path: string; from: number; to: number; - path: string; value: { attributes: Indexable; }; @@ -146,12 +146,13 @@ export type StyleOpInfo = { */ export type TreeEditOpInfo = { type: 'tree-edit'; + path: string; from: number; to: number; + value: TreeNode; + splitLevel: number; fromPath: Array; toPath: Array; - value: TreeNode; - path: string; }; /** @@ -159,11 +160,11 @@ export type TreeEditOpInfo = { */ export type TreeStyleOpInfo = { type: 'tree-style'; + path: string; from: number; to: number; fromPath: Array; value: { [key: string]: any }; - path: string; }; /** diff --git a/src/document/operation/tree_edit_operation.ts b/src/document/operation/tree_edit_operation.ts index 952869457..c48d504ed 100644 --- a/src/document/operation/tree_edit_operation.ts +++ b/src/document/operation/tree_edit_operation.ts @@ -35,20 +35,23 @@ export class TreeEditOperation extends Operation { private fromPos: CRDTTreePos; private toPos: CRDTTreePos; private contents: Array | undefined; + private splitLevel: number; private maxCreatedAtMapByActor: Map; constructor( parentCreatedAt: TimeTicket, fromPos: CRDTTreePos, toPos: CRDTTreePos, - maxCreatedAtMapByActor: Map, contents: Array | undefined, + splitLevel: number, + maxCreatedAtMapByActor: Map, executedAt: TimeTicket, ) { super(parentCreatedAt, executedAt); this.fromPos = fromPos; this.toPos = toPos; this.contents = contents; + this.splitLevel = splitLevel; this.maxCreatedAtMapByActor = maxCreatedAtMapByActor; } @@ -59,16 +62,18 @@ export class TreeEditOperation extends Operation { parentCreatedAt: TimeTicket, fromPos: CRDTTreePos, toPos: CRDTTreePos, - maxCreatedAtMapByActor: Map, contents: Array | undefined, + splitLevel: number, + maxCreatedAtMapByActor: Map, executedAt: TimeTicket, ): TreeEditOperation { return new TreeEditOperation( parentCreatedAt, fromPos, toPos, - maxCreatedAtMapByActor, contents, + splitLevel, + maxCreatedAtMapByActor, executedAt, ); } @@ -85,10 +90,10 @@ export class TreeEditOperation extends Operation { logger.fatal(`fail to execute, only Tree can execute edit`); } const tree = parentObject as CRDTTree; - // TODO(hackerwins): Implement splitLevels. const [changes] = tree.edit( [this.fromPos, this.toPos], this.contents?.map((content) => content.deepcopy()), + this.splitLevel, this.getExecutedAt(), this.maxCreatedAtMapByActor, ); @@ -97,17 +102,20 @@ export class TreeEditOperation extends Operation { root.registerElementHasRemovedNodes(tree); } return { - opInfos: changes.map(({ from, to, value, fromPath, toPath }) => { - return { - type: 'tree-edit', - from, - to, - value, - fromPath, - toPath, - path: root.createPath(this.getParentCreatedAt()), - } as OperationInfo; - }), + opInfos: changes.map( + ({ from, to, value, splitLevel, fromPath, toPath }) => { + return { + type: 'tree-edit', + path: root.createPath(this.getParentCreatedAt()), + from, + to, + value, + splitLevel, + fromPath, + toPath, + } as OperationInfo; + }, + ), }; } @@ -156,6 +164,13 @@ export class TreeEditOperation extends Operation { return this.contents; } + /** + * `getSplitLevel` returns the split level of Edit. + */ + public getSplitLevel(): number { + return this.splitLevel; + } + /** * `getMaxCreatedAtMapByActor` returns the map that stores the latest creation time * by actor for the nodes included in the editing range. diff --git a/src/util/index_tree.ts b/src/util/index_tree.ts index a6b450257..5178b4da0 100644 --- a/src/util/index_tree.ts +++ b/src/util/index_tree.ts @@ -180,17 +180,6 @@ export abstract class IndexTreeNode> { return undefined; } - /** - * `split` splits the node at the given offset. - */ - split(offset: number, absOffset: number): T | undefined { - if (this.isText) { - return this.splitText(offset, absOffset); - } - - return this.splitElement(offset); - } - /** * `isRemoved` returns true if the node is removed. */ @@ -360,8 +349,16 @@ export abstract class IndexTreeNode> { /** * `splitElement` splits the given element at the given offset. */ - splitElement(offset: number): T | undefined { - const clone = this.clone(offset); + splitElement(offset: number, absOffset: number): T | undefined { + /** + * TODO(hackerwins): Define ID of split node for concurrent editing. + * Text has fixed content and its split nodes could have limited offset + * range. But element node could have arbitrary children and its split + * nodes could have arbitrary offset range. So, id could be duplicated + * and its order could be broken when concurrent editing happens. + * Currently, we use the similar ID of split element with the split text. + */ + const clone = this.clone(offset + absOffset); this.parent!.insertAfterInternal(clone, this as any); clone.updateAncestorsSize(); @@ -754,25 +751,6 @@ export class IndexTree> { traverseAll(this.root, callback, 0); } - /** - * `split` splits the node at the given index. - */ - public split(index: number, depth = 1): TreePos { - const treePos = findTreePos(this.root, index, true); - - let node: T | undefined = treePos.node; - let offset: number = treePos.offset; - for (let i = 0; i < depth && node && node !== this.root; i++) { - node.split(offset, 0); - - const nextOffset = node.parent!.findOffset(node); - offset = offset === 0 ? nextOffset : nextOffset + 1; - node = node.parent; - } - - return treePos; - } - /** * findTreePos finds the position of the given index in the tree. */ diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index e34db0f50..6b8c0ecc0 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -628,12 +628,10 @@ describe('Tree.edit', function () { assert.equal(doc.getRoot().t.toXML(), /*html*/ `

ab

`); doc.update((root) => { - root.t.edit( - 3, - 3, + root.t.editBulk(3, 3, [ { type: 'text', value: 'c' }, { type: 'text', value: 'd' }, - ); + ]); }); assert.equal(doc.getRoot().t.toXML(), /*html*/ `

abcd

`); @@ -656,12 +654,10 @@ describe('Tree.edit', function () { assert.equal(doc.getRoot().t.toXML(), /*html*/ `

ab

`); doc.update((root) => { - root.t.edit( - 4, - 4, + root.t.editBulk(4, 4, [ { type: 'p', children: [{ type: 'text', value: 'cd' }] }, { type: 'i', children: [{ type: 'text', value: 'fg' }] }, - ); + ]); }); assert.equal( @@ -698,78 +694,84 @@ describe('Tree.edit', function () { /*html*/ `

ab

`, ); - root.t.editByPath( + root.t.editBulkByPath( [0, 0, 0, 1], [0, 0, 0, 1], - { - type: 'text', - value: 'X', - }, - { - type: 'text', - value: 'X', - }, + [ + { + type: 'text', + value: 'X', + }, + { + type: 'text', + value: 'X', + }, + ], ); assert.equal( root.t.toXML(), /*html*/ `

aXXb

`, ); - root.t.editByPath( + root.t.editBulkByPath( [0, 1], [0, 1], - { - type: 'p', - children: [ - { - type: 'tn', - children: [ - { type: 'text', value: 'te' }, - { type: 'text', value: 'st' }, - ], - }, - ], - }, - { - type: 'p', - children: [ - { - type: 'tn', - children: [ - { type: 'text', value: 'te' }, - { type: 'text', value: 'xt' }, - ], - }, - ], - }, + [ + { + type: 'p', + children: [ + { + type: 'tn', + children: [ + { type: 'text', value: 'te' }, + { type: 'text', value: 'st' }, + ], + }, + ], + }, + { + type: 'p', + children: [ + { + type: 'tn', + children: [ + { type: 'text', value: 'te' }, + { type: 'text', value: 'xt' }, + ], + }, + ], + }, + ], ); assert.equal( root.t.toXML(), /*html*/ `

aXXb

test

text

`, ); - root.t.editByPath( + root.t.editBulkByPath( [0, 3], [0, 3], - { - type: 'p', - children: [ - { - type: 'tn', - children: [ - { type: 'text', value: 'te' }, - { type: 'text', value: 'st' }, - ], - }, - ], - }, - { - type: 'tn', - children: [ - { type: 'text', value: 'te' }, - { type: 'text', value: 'xt' }, - ], - }, + [ + { + type: 'p', + children: [ + { + type: 'tn', + children: [ + { type: 'text', value: 'te' }, + { type: 'text', value: 'st' }, + ], + }, + ], + }, + { + type: 'tn', + children: [ + { type: 'text', value: 'te' }, + { type: 'text', value: 'xt' }, + ], + }, + ], ); assert.equal( root.t.toXML(), @@ -796,12 +798,10 @@ describe('Tree.edit', function () { assert.Throw(() => { doc.update((root) => { - root.t.edit( - 3, - 3, + root.t.editBulk(3, 3, [ { type: 'text', value: 'c' }, { type: 'text', value: '' }, - ); + ]); }); }, 'text node cannot have empty value'); }); @@ -824,12 +824,10 @@ describe('Tree.edit', function () { assert.Throw(() => { doc.update((root) => { - root.t.edit( - 3, - 3, + root.t.editBulk(3, 3, [ { type: 'p', children: [] }, { type: 'text', value: 'd' }, - ); + ]); }); }, 'element node and text node cannot be passed together'); }); @@ -852,9 +850,7 @@ describe('Tree.edit', function () { assert.Throw(() => { doc.update((root) => { - root.t.edit( - 3, - 3, + root.t.editBulk(3, 3, [ { type: 'p', children: [ @@ -863,7 +859,7 @@ describe('Tree.edit', function () { ], }, { type: 'text', value: 'd' }, - ); + ]); }); }, 'element node and text node cannot be passed together'); }); @@ -886,12 +882,10 @@ describe('Tree.edit', function () { assert.Throw(() => { doc.update((root) => { - root.t.edit( - 3, - 3, + root.t.editBulk(3, 3, [ { type: 'p', children: [{ type: 'text', value: 'c' }] }, { type: 'p', children: [{ type: 'text', value: '' }] }, - ); + ]); }); }, 'text node cannot have empty value'); }); @@ -914,12 +908,10 @@ describe('Tree.edit', function () { assert.Throw(() => { doc.update((root) => { - root.t.edit( - 3, - 3, + root.t.editBulk(3, 3, [ { type: 'text', value: 'd' }, { type: 'p', children: [{ type: 'text', value: 'c' }] }, - ); + ]); }); }, 'element node and text node cannot be passed together'); }); @@ -2176,12 +2168,10 @@ describe('Concurrent editing, complex cases', () => { d1.update((r) => r.t.edit(2, 6)); d2.update((r) => - r.t.edit( - 3, - 3, + r.t.editBulk(3, 3, [ { type: 'text', value: 'a' }, { type: 'text', value: 'bc' }, - ), + ]), ); assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1

`); assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12abc345

`); @@ -2220,12 +2210,10 @@ describe('Concurrent editing, complex cases', () => { d1.update((r) => r.t.edit(0, 12)); d2.update((r) => - r.t.edit( - 6, - 6, + r.t.editBulk(6, 6, [ { type: 'p', children: [{ type: 'text', value: 'cd' }] }, { type: 'i', children: [{ type: 'text', value: 'fg' }] }, - ), + ]), ); assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); assert.equal( @@ -2266,12 +2254,10 @@ describe('Concurrent editing, complex cases', () => { d1.update((r) => r.t.edit(0, 7)); d2.update((r) => - r.t.edit( - 0, - 0, + r.t.editBulk(0, 0, [ { type: 'p', children: [{ type: 'text', value: 'cd' }] }, { type: 'i', children: [{ type: 'text', value: 'fg' }] }, - ), + ]), ); assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); assert.equal( @@ -2312,12 +2298,10 @@ describe('Concurrent editing, complex cases', () => { d1.update((r) => r.t.edit(0, 7)); d2.update((r) => - r.t.edit( - 7, - 7, + r.t.editBulk(7, 7, [ { type: 'p', children: [{ type: 'text', value: 'cd' }] }, { type: 'i', children: [{ type: 'text', value: 'fg' }] }, - ), + ]), ); assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); @@ -2591,4 +2575,36 @@ describe('testing edge cases', () => { assert.equal(d2.getRoot().t.getIndexTree().getRoot().size, size); }, task.name); }); + + it('can split and merge with empty paragraph', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'a' }, + { type: 'text', value: 'b' }, + ], + }, + ], + }); + }); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + + d1.update((root) => root.t.edit(3, 3, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + d1.update((root) => root.t.edit(3, 5)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + }, task.name); + }); }); diff --git a/test/unit/document/crdt/tree_test.ts b/test/unit/document/crdt/tree_test.ts index b52bc4215..5085e9abd 100644 --- a/test/unit/document/crdt/tree_test.ts +++ b/test/unit/document/crdt/tree_test.ts @@ -80,7 +80,7 @@ describe('CRDTTreeNode', function () { assert.equal(para.isText, false); const left = para.children[0]; - const right = left.split(5, 0); + const right = left.splitText(5, 0); assert.equal(toXML(para), /*html*/ `

helloyorkie

`); assert.equal(para.size, 11); @@ -102,13 +102,13 @@ describe('CRDTTree.Edit', function () { // 1 //

- t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); assert.equal(t.toXML(), /*html*/ `

`); assert.equal(t.getRoot().size, 2); // 1 //

h e l l o

- t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'hello')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'hello')], 0, timeT()); assert.equal(t.toXML(), /*html*/ `

hello

`); assert.equal(t.getRoot().size, 7); @@ -116,13 +116,13 @@ describe('CRDTTree.Edit', function () { //

h e l l o

w o r l d

const p = new CRDTTreeNode(posT(), 'p', []); p.insertAt(new CRDTTreeNode(posT(), 'text', 'world'), 0); - t.editT([7, 7], [p], timeT()); + t.editT([7, 7], [p], 0, timeT()); assert.equal(t.toXML(), /*html*/ `

hello

world

`); assert.equal(t.getRoot().size, 14); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //

h e l l o !

w o r l d

- t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '!')], timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '!')], 0, timeT()); assert.equal(t.toXML(), /*html*/ `

hello!

world

`); assert.deepEqual(t.toTestTreeNode(), { @@ -152,7 +152,7 @@ describe('CRDTTree.Edit', function () { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //

h e l l o ~ !

w o r l d

- t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '~')], timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '~')], 0, timeT()); assert.equal(t.toXML(), /*html*/ `

hello~!

world

`); }); @@ -161,10 +161,10 @@ describe('CRDTTree.Edit', function () { // 0 1 2 3 4 5 6 7 8 //

a b

c d

const tree = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - tree.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - tree.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); - tree.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], timeT()); - tree.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); + tree.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + tree.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + tree.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + tree.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); assert.deepEqual(tree.toXML(), /*html*/ `

ab

cd

`); let treeNode = tree.toTestTreeNode(); @@ -175,7 +175,7 @@ describe('CRDTTree.Edit', function () { // 02. delete b from first paragraph // 0 1 2 3 4 5 6 7 //

a

c d

- tree.editT([2, 3], undefined, timeT()); + tree.editT([2, 3], undefined, 0, timeT()); assert.deepEqual(tree.toXML(), /*html*/ `

a

cd

`); treeNode = tree.toTestTreeNode(); @@ -192,17 +192,17 @@ describe('CRDTTree.Edit', function () { // 0 1 2 3 4 //

a b

- t.editT([0, 0], [pNode], timeT()); - t.editT([1, 1], [textNode], timeT()); + t.editT([0, 0], [pNode], 0, timeT()); + t.editT([1, 1], [textNode], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // Find the closest index.TreePos when leftSiblingNode in crdt.TreePos is removed. // 0 1 2 //

- t.editT([1, 3], undefined, timeT()); + t.editT([1, 3], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

`); - let [parent, left] = t.findNodesAndSplit( + let [parent, left] = t.findNodesAndSplitText( new CRDTTreePos(pNode.id, textNode.id), timeT(), ); @@ -211,10 +211,10 @@ describe('CRDTTree.Edit', function () { // Find the closest index.TreePos when parentNode in crdt.TreePos is removed. // 0 // - t.editT([0, 2], undefined, timeT()); + t.editT([0, 2], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ ``); - [parent, left] = t.findNodesAndSplit( + [parent, left] = t.findNodesAndSplitText( new CRDTTreePos(pNode.id, textNode.id), timeT(), ); @@ -228,8 +228,13 @@ describe('CRDTTree.Split', function () { // 0 1 6 11 //

hello world

const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'helloworld')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'helloworld')], + 0, + timeT(), + ); const expectedIntial = { type: 'root', children: [ @@ -248,15 +253,15 @@ describe('CRDTTree.Split', function () { assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 01. Split left side of 'helloworld'. - t.editT([1, 1], undefined, timeT()); + t.editT([1, 1], undefined, 0, timeT()); assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 02. Split right side of 'helloworld'. - t.editT([11, 11], undefined, timeT()); + t.editT([11, 11], undefined, 0, timeT()); assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 03. Split 'helloworld' into 'hello' and 'world'. - t.editT([6, 6], undefined, timeT()); + t.editT([6, 6], undefined, 0, timeT()); assert.deepEqual(t.toTestTreeNode(), { type: 'root', children: [ @@ -275,49 +280,49 @@ describe('CRDTTree.Split', function () { }); }); - it.skip('Can split element nodes level 1', function () { + it('Can split element nodes level 1', function () { // 0 1 2 3 4 //

a b

// 01. Split position 1. let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - // t.editT([1, 1], undefined, [1, 1], timeT()); + t.editT([1, 1], undefined, 1, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); assert.equal(t.getSize(), 6); // 02. Split position 2. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - // t.editT([2, 2], undefined, [1, 1], timeT()); + t.editT([2, 2], undefined, 1, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

a

b

`); assert.equal(t.getSize(), 6); // 03. Split position 3. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - // t.editT([3, 3], undefined, [1, 1], timeT()); + t.editT([3, 3], undefined, 1, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); assert.equal(t.getSize(), 6); }); - it.skip('Can split element nodes multi-level', function () { + it('Can split element nodes multi-level', function () { // 0 1 2 3 4 5 6 //

a b

// 01. Split nodes level 1. let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - // t.editT([3, 3], undefined, [1, 1], timeT()); + t.editT([3, 3], undefined, 1, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, @@ -325,43 +330,31 @@ describe('CRDTTree.Split', function () { // 02. Split nodes level 2. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); - assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - // t.editT([3, 3], undefined, [2, 2], timeT()); - assert.deepEqual( - t.toXML(), - /*html*/ `

a

b

`, - ); - - // Split multiple nodes level 3. But, it is allowed to split only level 2. - t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - // t.editT([3, 3], undefined, [3, 3], timeT()); + t.editT([3, 3], undefined, 2, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

a

b

`, ); }); - it.skip('Can split and merge element nodes by edit', function () { + it('Can split and merge element nodes by edit', function () { const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'abcd')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'abcd')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

abcd

`); assert.equal(t.getSize(), 6); // 0 1 2 3 4 5 6 7 8 //

a b

c d

- // tree.split(3, 2); + t.editT([3, 3], undefined, 1, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

cd

`); assert.equal(t.getSize(), 8); - t.editT([3, 5], undefined, timeT()); + t.editT([3, 5], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

abcd

`); assert.equal(t.getSize(), 6); }); @@ -373,16 +366,16 @@ describe('CRDTTree.Merge', function () { // 0 1 2 3 4 5 6 7 8 //

a b

c d

const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); - t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

cd

`); // 02. delete b, c and the second paragraph. // 0 1 2 3 4 //

a d

- t.editT([2, 6], undefined, timeT()); + t.editT([2, 6], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ad

`); const node = t.toTestTreeNode(); @@ -392,7 +385,7 @@ describe('CRDTTree.Merge', function () { assert.equal(node.children![0].children![1].size, 1); // d // 03. insert a new text node at the start of the first paragraph. - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', '@')], timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', '@')], 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

@ad

`); }); @@ -401,11 +394,11 @@ describe('CRDTTree.Merge', function () { // 0 1 2 3 4 5 6 7 8 9 10 //

a b

c d

const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); - t.editT([6, 6], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([7, 7], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([7, 7], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

cd

`, @@ -414,7 +407,7 @@ describe('CRDTTree.Merge', function () { // 02. delete b, c and second paragraph. // 0 1 2 3 4 5 //

a d - t.editT([3, 8], undefined, timeT()); + t.editT([3, 8], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ad

`); }); @@ -424,96 +417,96 @@ describe('CRDTTree.Merge', function () { // 0 1 2 3 4 5 6 7 8 //

a b

let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([5, 6], undefined, timeT()); + t.editT([5, 6], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 02. edit between two element nodes in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([6, 7], undefined, timeT()); + t.editT([6, 7], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 03. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([4, 6], undefined, timeT()); + t.editT([4, 6], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

a

`); // 04. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([5, 7], undefined, timeT()); + t.editT([5, 7], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 05. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([4, 7], undefined, timeT()); + t.editT([4, 7], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

a

`); // 06. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); + t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([3, 7], undefined, timeT()); + t.editT([3, 7], undefined, 0, timeT()); assert.deepEqual(t.toXML(), /*html*/ `

`); // 07. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], timeT()); - t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([5, 5], [new CRDTTreeNode(posT(), 'b')], timeT()); - t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', 'cd')], timeT()); - t.editT([10, 10], [new CRDTTreeNode(posT(), 'p')], timeT()); - t.editT([11, 11], [new CRDTTreeNode(posT(), 'text', 'ef')], timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([5, 5], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); + t.editT([10, 10], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([11, 11], [new CRDTTreeNode(posT(), 'text', 'ef')], 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

cd

ef

`, ); - t.editT([9, 10], undefined, timeT()); + t.editT([9, 10], undefined, 0, timeT()); assert.deepEqual( t.toXML(), /*html*/ `

ab

cd

ef

`, From 5be4296e5924b398003bd8c27fb16f82070445ad Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 4 Dec 2023 21:54:36 +0900 Subject: [PATCH 14/48] Update CHANGELOG.md for v0.4.10 (#706) --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b74528d20..41768f2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +## [0.4.10] - 2023-12-04 + +### Added + +* Add create-yorkie-app by @se030, @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/690 +* Implement splitLevel of Tree.Edit by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/704 +* Add `removeIfNotAttached` to `client.detach()` options by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/703 + +### Fixed +* Fix reading wrong .env path by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/694 +* Handle escape string for strings containing quotes by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/700 +* Correct typos in the installation command on README.md in the example by @ymw0407 in https://github.com/yorkie-team/yorkie-js-sdk/pull/702 + ## [0.4.9] - 2023-11-25 ### Added diff --git a/package.json b/package.json index 175d93c5e..057f239f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.9", + "version": "0.4.10", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index 07d1bf5b4..aee2a3a64 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.9", + "version": "0.4.10", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 438ceacf56f03174052ced5890b8cc8412ed37c2 Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:57:10 +0900 Subject: [PATCH 15/48] Add test filtering and log printing guide to CONTRIBUTING.md (#708) Co-authored-by: Youngteac Hong --- CONTRIBUTING.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0cad78d15..fae44c4e7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,6 +82,34 @@ $ docker pull yorkieteam/yorkie:latest $ docker-compose -f docker/docker-compose.yml up --build -d ``` +To print specific console logs, delete the line `return false` in the `onConsoleLog()` function within [`vitest.config.ts`](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/vitest.config.ts#L16). +```ts +export default defineConfig({ + test: { + include: ['**/*_{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + exclude: ['**/bench/*'], + coverage: { + provider: 'istanbul', + reporter: ['lcov', 'text-summary'], + }, + onConsoleLog() { + return false; // <<------ delete here. + }, + environment: 'custom-jsdom', + globals: true, + testTimeout: isCI ? 5000 : Infinity, + }, + plugins: [tsconfigPaths()], +}); + +``` + +To run only specific suites or tests, use `.only` and execute the following command with the path to the desired test file. +Refer to [Test Filtering](https://vitest.dev/guide/filtering#selecting-suites-and-tests-to-run) in `vitest` for more details: +```bash +$ npm run test {test file path} # e.g. npm run test integration/tree_test.ts +``` + ### Starting co-editing example with CodeMirror Start MongoDB, Yorkie and Envoy proxy in a terminal session. From 42fb01cb8da1537483c3163f2fb913dfdf586d34 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Wed, 13 Dec 2023 17:36:34 +0900 Subject: [PATCH 16/48] Address duplicate node IDs in Tree.Split (#707) We need to define ID of split element node for concurrent editing. Text has fixed content and its split nodes could have limited offset range. But element node could have arbitrary children and its split nodes could have arbitrary offset range. So, id could be duplicated and its order could be broken when concurrent editing happens. This commit temporarily avoids duplication by issuing a new ID. --------- Co-authored-by: Sejong Kim --- src/document/crdt/tree.ts | 37 ++- src/document/json/tree.ts | 1 + src/document/operation/tree_edit_operation.ts | 23 +- src/document/time/ticket.ts | 7 + src/util/index_tree.ts | 21 +- test/integration/tree_test.ts | 208 +++++++++++- test/unit/document/crdt/tree_test.ts | 311 +++++++++++++----- 7 files changed, 506 insertions(+), 102 deletions(-) diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index 4c26067e4..fe66b5c3e 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -494,9 +494,9 @@ export class CRDTTreeNode extends IndexTreeNode { } /** - * `clone` clones this node with the given offset. + * `cloneText` clones this text node with the given offset. */ - clone(offset: number): CRDTTreeNode { + cloneText(offset: number): CRDTTreeNode { return new CRDTTreeNode( CRDTTreeNodeID.of(this.id.getCreatedAt(), offset), this.type, @@ -506,13 +506,30 @@ export class CRDTTreeNode extends IndexTreeNode { ); } + /** + * `cloneElement` clones this element node with the given issueTimeTicket function. + */ + cloneElement(issueTimeTicket: () => TimeTicket): CRDTTreeNode { + return new CRDTTreeNode( + CRDTTreeNodeID.of(issueTimeTicket(), 0), + this.type, + undefined, + undefined, + this.removedAt, + ); + } + /** * `split` splits the given offset of this node. */ - public split(tree: CRDTTree, offset: number): CRDTTreeNode | undefined { + public split( + tree: CRDTTree, + offset: number, + issueTimeTicket?: () => TimeTicket, + ): CRDTTreeNode | undefined { const split = this.isText ? this.splitText(offset, this.id.getOffset()) - : this.splitElement(offset, this.id.getOffset()); + : this.splitElement(offset, issueTimeTicket!); if (split) { split.insPrevID = this.id; @@ -744,6 +761,7 @@ export class CRDTTree extends CRDTGCElement { contents: Array | undefined, splitLevel: number, editedAt: TimeTicket, + issueTimeTicket: (() => TimeTicket) | undefined, latestCreatedAtMapByActor?: Map, ): [Array, Map] { // 01. find nodes from the given range and split nodes. @@ -843,7 +861,7 @@ export class CRDTTree extends CRDTGCElement { let parent = fromParent; let left = fromLeft; while (splitCount < splitLevel) { - parent.split(this, parent.findOffset(left) + 1); + parent.split(this, parent.findOffset(left) + 1, issueTimeTicket); left = parent; parent = parent.parent!; splitCount++; @@ -890,10 +908,17 @@ export class CRDTTree extends CRDTGCElement { contents: Array | undefined, splitLevel: number, editedAt: TimeTicket, + issueTimeTicket: () => TimeTicket, ): void { const fromPos = this.findPos(range[0]); const toPos = this.findPos(range[1]); - this.edit([fromPos, toPos], contents, splitLevel, editedAt); + this.edit( + [fromPos, toPos], + contents, + splitLevel, + editedAt, + issueTimeTicket, + ); } /** diff --git a/src/document/json/tree.ts b/src/document/json/tree.ts index a0a000a95..3b3af5f19 100644 --- a/src/document/json/tree.ts +++ b/src/document/json/tree.ts @@ -370,6 +370,7 @@ export class Tree { : undefined, splitLevel, ticket, + () => this.context!.issueTimeTicket(), ); this.context!.push( diff --git a/src/document/operation/tree_edit_operation.ts b/src/document/operation/tree_edit_operation.ts index c48d504ed..d0e7704a7 100644 --- a/src/document/operation/tree_edit_operation.ts +++ b/src/document/operation/tree_edit_operation.ts @@ -89,12 +89,33 @@ export class TreeEditOperation extends Operation { if (!(parentObject instanceof CRDTTree)) { logger.fatal(`fail to execute, only Tree can execute edit`); } + const editedAt = this.getExecutedAt(); const tree = parentObject as CRDTTree; const [changes] = tree.edit( [this.fromPos, this.toPos], this.contents?.map((content) => content.deepcopy()), this.splitLevel, - this.getExecutedAt(), + editedAt, + /** + * TODO(sejongk): When splitting element nodes, a new nodeID is assigned with a different timeTicket. + * In the same change context, the timeTickets share the same lamport and actorID but have different delimiters, + * incremented by one for each. + * Therefore, it is possible to simulate later timeTickets using `editedAt` and the length of `contents`. + * This logic might be unclear; consider refactoring for multi-level concurrent editing in the Tree implementation. + */ + (() => { + let delimiter = editedAt.getDelimiter(); + if (this.contents !== undefined) { + delimiter += this.contents.length; + } + const issueTimeTicket = () => + TimeTicket.of( + editedAt.getLamport(), + ++delimiter, + editedAt.getActorID(), + ); + return issueTimeTicket; + })(), this.maxCreatedAtMapByActor, ); diff --git a/src/document/time/ticket.ts b/src/document/time/ticket.ts index 4407fe21b..4c2ad74aa 100644 --- a/src/document/time/ticket.ts +++ b/src/document/time/ticket.ts @@ -127,6 +127,13 @@ export class TimeTicket { return this.lamport.toString(); } + /** + * `getLamport` returns the lamport. + */ + public getLamport(): Long { + return this.lamport; + } + /** * `getDelimiter` returns delimiter. */ diff --git a/src/util/index_tree.ts b/src/util/index_tree.ts index 5178b4da0..e09ce495a 100644 --- a/src/util/index_tree.ts +++ b/src/util/index_tree.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { TimeTicket } from '../yorkie'; + /** * About `index`, `path`, `size` and `TreePos` in crdt.IndexTree. * @@ -186,9 +188,15 @@ export abstract class IndexTreeNode> { abstract get isRemoved(): boolean; /** - * `clone` clones the node with the given id and value. + * `cloneText` clones the text node with the given id and value. + */ + abstract cloneText(offset: number): T; + + /** + * `cloneElement` clones the element node with the given issueTimeTicket + * function and value. */ - abstract clone(offset: number): T; + abstract cloneElement(issueTimeTicket: () => TimeTicket): T; /** * `value` returns the value of the node. @@ -217,7 +225,7 @@ export abstract class IndexTreeNode> { this.value = leftValue; - const rightNode = this.clone(offset + absOffset); + const rightNode = this.cloneText(offset + absOffset); rightNode.value = rightValue; this.parent!.insertAfterInternal(rightNode, this as any); @@ -349,7 +357,10 @@ export abstract class IndexTreeNode> { /** * `splitElement` splits the given element at the given offset. */ - splitElement(offset: number, absOffset: number): T | undefined { + splitElement( + offset: number, + issueTimeTicket: () => TimeTicket, + ): T | undefined { /** * TODO(hackerwins): Define ID of split node for concurrent editing. * Text has fixed content and its split nodes could have limited offset @@ -358,7 +369,7 @@ export abstract class IndexTreeNode> { * and its order could be broken when concurrent editing happens. * Currently, we use the similar ID of split element with the split text. */ - const clone = this.clone(offset + absOffset); + const clone = this.cloneElement(issueTimeTicket); this.parent!.insertAfterInternal(clone, this as any); clone.updateAncestorsSize(); diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index 6b8c0ecc0..6927d98dd 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -2576,7 +2576,43 @@ describe('testing edge cases', () => { }, task.name); }); - it('can split and merge with empty paragraph', async function ({ task }) { + it('can split and merge with empty paragraph: left', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'a' }, + { type: 'text', value: 'b' }, + ], + }, + ], + }); + }); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + + d1.update((root) => root.t.edit(1, 1, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + d1.update((root) => root.t.edit(1, 3)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + }, task.name); + }); + + it('can split and merge with empty paragraph: right', async function ({ + task, + }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -2607,4 +2643,174 @@ describe('testing edge cases', () => { assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); }, task.name); }); + + it('can split and merge with empty paragraph and multiple split level: left', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { + type: 'p', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'a' }, + { type: 'text', value: 'b' }, + ], + }, + ], + }, + ], + }); + }); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + + d1.update((root) => root.t.edit(2, 2, undefined, 2)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + d1.update((root) => root.t.edit(2, 6)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + }, task.name); + }); + + it('split at the same offset multiple times', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'a' }, + { type: 'text', value: 'b' }, + ], + }, + ], + }); + }); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + + d1.update((root) => root.t.edit(2, 2, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

`, + ); + + d1.update((root) => root.t.edit(2, 2, { type: 'text', value: 'c' })); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ac

b

`, + ); + + d1.update((root) => root.t.edit(2, 2, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

c

b

`, + ); + + d1.update((root) => root.t.edit(2, 7, undefined)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + }, task.name); + }); + + it('Can concurrently split and insert into original node', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'a' }, + { type: 'text', value: 'b' }, + { type: 'text', value: 'c' }, + { type: 'text', value: 'd' }, + ], + }, + ], + }); + }); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abcd

`); + await c1.sync(); + await c2.sync(); + + d1.update((root) => root.t.edit(3, 3, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); + + d2.update((root) => root.t.edit(2, 2, { type: 'text', value: 'e' })); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

aebcd

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + }, task.name); + }); + + it.skip('Can concurrently split and insert into split node', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { + type: 'p', + children: [ + { type: 'text', value: 'a' }, + { type: 'text', value: 'b' }, + { type: 'text', value: 'c' }, + { type: 'text', value: 'd' }, + ], + }, + ], + }); + }); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abcd

`); + await c1.sync(); + await c2.sync(); + + d1.update((root) => root.t.edit(3, 3, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); + + d2.update((root) => root.t.edit(4, 4, { type: 'text', value: 'e' })); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

abced

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + }, task.name); + }); }); diff --git a/test/unit/document/crdt/tree_test.ts b/test/unit/document/crdt/tree_test.ts index 5085e9abd..07332c3f6 100644 --- a/test/unit/document/crdt/tree_test.ts +++ b/test/unit/document/crdt/tree_test.ts @@ -102,13 +102,19 @@ describe('CRDTTree.Edit', function () { // 1 //

- t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); assert.equal(t.toXML(), /*html*/ `

`); assert.equal(t.getRoot().size, 2); // 1 //

h e l l o

- t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'hello')], 0, timeT()); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'hello')], + 0, + timeT(), + timeT, + ); assert.equal(t.toXML(), /*html*/ `

hello

`); assert.equal(t.getRoot().size, 7); @@ -116,13 +122,13 @@ describe('CRDTTree.Edit', function () { //

h e l l o

w o r l d

const p = new CRDTTreeNode(posT(), 'p', []); p.insertAt(new CRDTTreeNode(posT(), 'text', 'world'), 0); - t.editT([7, 7], [p], 0, timeT()); + t.editT([7, 7], [p], 0, timeT(), timeT); assert.equal(t.toXML(), /*html*/ `

hello

world

`); assert.equal(t.getRoot().size, 14); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //

h e l l o !

w o r l d

- t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '!')], 0, timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '!')], 0, timeT(), timeT); assert.equal(t.toXML(), /*html*/ `

hello!

world

`); assert.deepEqual(t.toTestTreeNode(), { @@ -152,7 +158,7 @@ describe('CRDTTree.Edit', function () { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //

h e l l o ~ !

w o r l d

- t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '~')], 0, timeT()); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', '~')], 0, timeT(), timeT); assert.equal(t.toXML(), /*html*/ `

hello~!

world

`); }); @@ -161,10 +167,22 @@ describe('CRDTTree.Edit', function () { // 0 1 2 3 4 5 6 7 8 //

a b

c d

const tree = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - tree.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - tree.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); - tree.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - tree.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); + tree.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + tree.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); + tree.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + tree.editT( + [5, 5], + [new CRDTTreeNode(posT(), 'text', 'cd')], + 0, + timeT(), + timeT, + ); assert.deepEqual(tree.toXML(), /*html*/ `

ab

cd

`); let treeNode = tree.toTestTreeNode(); @@ -175,7 +193,7 @@ describe('CRDTTree.Edit', function () { // 02. delete b from first paragraph // 0 1 2 3 4 5 6 7 //

a

c d

- tree.editT([2, 3], undefined, 0, timeT()); + tree.editT([2, 3], undefined, 0, timeT(), timeT); assert.deepEqual(tree.toXML(), /*html*/ `

a

cd

`); treeNode = tree.toTestTreeNode(); @@ -192,14 +210,14 @@ describe('CRDTTree.Edit', function () { // 0 1 2 3 4 //

a b

- t.editT([0, 0], [pNode], 0, timeT()); - t.editT([1, 1], [textNode], 0, timeT()); + t.editT([0, 0], [pNode], 0, timeT(), timeT); + t.editT([1, 1], [textNode], 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // Find the closest index.TreePos when leftSiblingNode in crdt.TreePos is removed. // 0 1 2 //

- t.editT([1, 3], undefined, 0, timeT()); + t.editT([1, 3], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

`); let [parent, left] = t.findNodesAndSplitText( @@ -211,7 +229,7 @@ describe('CRDTTree.Edit', function () { // Find the closest index.TreePos when parentNode in crdt.TreePos is removed. // 0 // - t.editT([0, 2], undefined, 0, timeT()); + t.editT([0, 2], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ ``); [parent, left] = t.findNodesAndSplitText( @@ -228,12 +246,13 @@ describe('CRDTTree.Split', function () { // 0 1 6 11 //

hello world

const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); t.editT( [1, 1], [new CRDTTreeNode(posT(), 'text', 'helloworld')], 0, timeT(), + timeT, ); const expectedIntial = { type: 'root', @@ -253,15 +272,15 @@ describe('CRDTTree.Split', function () { assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 01. Split left side of 'helloworld'. - t.editT([1, 1], undefined, 0, timeT()); + t.editT([1, 1], undefined, 0, timeT(), timeT); assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 02. Split right side of 'helloworld'. - t.editT([11, 11], undefined, 0, timeT()); + t.editT([11, 11], undefined, 0, timeT(), timeT); assert.deepEqual(t.toTestTreeNode(), expectedIntial); // 03. Split 'helloworld' into 'hello' and 'world'. - t.editT([6, 6], undefined, 0, timeT()); + t.editT([6, 6], undefined, 0, timeT(), timeT); assert.deepEqual(t.toTestTreeNode(), { type: 'root', children: [ @@ -286,28 +305,46 @@ describe('CRDTTree.Split', function () { // 01. Split position 1. let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - t.editT([1, 1], undefined, 1, timeT()); + t.editT([1, 1], undefined, 1, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); assert.equal(t.getSize(), 6); // 02. Split position 2. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - t.editT([2, 2], undefined, 1, timeT()); + t.editT([2, 2], undefined, 1, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

a

b

`); assert.equal(t.getSize(), 6); // 03. Split position 3. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - t.editT([3, 3], undefined, 1, timeT()); + t.editT([3, 3], undefined, 1, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); assert.equal(t.getSize(), 6); }); @@ -318,11 +355,17 @@ describe('CRDTTree.Split', function () { // 01. Split nodes level 1. let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT( + [2, 2], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - t.editT([3, 3], undefined, 1, timeT()); + t.editT([3, 3], undefined, 1, timeT(), timeT); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, @@ -330,11 +373,17 @@ describe('CRDTTree.Split', function () { // 02. Split nodes level 2. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT( + [2, 2], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); - t.editT([3, 3], undefined, 2, timeT()); + t.editT([3, 3], undefined, 2, timeT(), timeT); assert.deepEqual( t.toXML(), /*html*/ `

a

b

`, @@ -343,18 +392,24 @@ describe('CRDTTree.Split', function () { it('Can split and merge element nodes by edit', function () { const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'abcd')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'abcd')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

abcd

`); assert.equal(t.getSize(), 6); // 0 1 2 3 4 5 6 7 8 //

a b

c d

- t.editT([3, 3], undefined, 1, timeT()); + t.editT([3, 3], undefined, 1, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

cd

`); assert.equal(t.getSize(), 8); - t.editT([3, 5], undefined, 0, timeT()); + t.editT([3, 5], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

abcd

`); assert.equal(t.getSize(), 6); }); @@ -366,16 +421,28 @@ describe('CRDTTree.Merge', function () { // 0 1 2 3 4 5 6 7 8 //

a b

c d

const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); - t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([5, 5], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); + t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [5, 5], + [new CRDTTreeNode(posT(), 'text', 'cd')], + 0, + timeT(), + timeT, + ); assert.deepEqual(t.toXML(), /*html*/ `

ab

cd

`); // 02. delete b, c and the second paragraph. // 0 1 2 3 4 //

a d

- t.editT([2, 6], undefined, 0, timeT()); + t.editT([2, 6], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ad

`); const node = t.toTestTreeNode(); @@ -385,7 +452,7 @@ describe('CRDTTree.Merge', function () { assert.equal(node.children![0].children![1].size, 1); // d // 03. insert a new text node at the start of the first paragraph. - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', '@')], 0, timeT()); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', '@')], 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

@ad

`); }); @@ -394,11 +461,23 @@ describe('CRDTTree.Merge', function () { // 0 1 2 3 4 5 6 7 8 9 10 //

a b

c d

const t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); - t.editT([6, 6], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([7, 7], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT( + [2, 2], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); + t.editT([6, 6], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [7, 7], + [new CRDTTreeNode(posT(), 'text', 'cd')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

cd

`, @@ -407,7 +486,7 @@ describe('CRDTTree.Merge', function () { // 02. delete b, c and second paragraph. // 0 1 2 3 4 5 //

a d - t.editT([3, 8], undefined, 0, timeT()); + t.editT([3, 8], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ad

`); }); @@ -417,96 +496,150 @@ describe('CRDTTree.Merge', function () { // 0 1 2 3 4 5 6 7 8 //

a b

let t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT(), timeT); + t.editT( + [3, 3], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([5, 6], undefined, 0, timeT()); + t.editT([5, 6], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 02. edit between two element nodes in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT(), timeT); + t.editT( + [3, 3], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([6, 7], undefined, 0, timeT()); + t.editT([6, 7], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 03. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT(), timeT); + t.editT( + [3, 3], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([4, 6], undefined, 0, timeT()); + t.editT([4, 6], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

a

`); // 04. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT(), timeT); + t.editT( + [3, 3], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([5, 7], undefined, 0, timeT()); + t.editT([5, 7], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

ab

`); // 05. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT(), timeT); + t.editT( + [3, 3], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([4, 7], undefined, 0, timeT()); + t.editT([4, 7], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

a

`); // 06. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT()); - t.editT([3, 3], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([1, 1], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT([2, 2], [new CRDTTreeNode(posT(), 'i')], 0, timeT(), timeT); + t.editT( + [3, 3], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

`, ); - t.editT([3, 7], undefined, 0, timeT()); + t.editT([3, 7], undefined, 0, timeT(), timeT); assert.deepEqual(t.toXML(), /*html*/ `

`); // 07. edit between text and element node in same hierarchy. t = new CRDTTree(new CRDTTreeNode(posT(), 'root'), timeT()); - t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([1, 1], [new CRDTTreeNode(posT(), 'text', 'ab')], 0, timeT()); - t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([5, 5], [new CRDTTreeNode(posT(), 'b')], 0, timeT()); - t.editT([6, 6], [new CRDTTreeNode(posT(), 'text', 'cd')], 0, timeT()); - t.editT([10, 10], [new CRDTTreeNode(posT(), 'p')], 0, timeT()); - t.editT([11, 11], [new CRDTTreeNode(posT(), 'text', 'ef')], 0, timeT()); + t.editT([0, 0], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [1, 1], + [new CRDTTreeNode(posT(), 'text', 'ab')], + 0, + timeT(), + timeT, + ); + t.editT([4, 4], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT([5, 5], [new CRDTTreeNode(posT(), 'b')], 0, timeT(), timeT); + t.editT( + [6, 6], + [new CRDTTreeNode(posT(), 'text', 'cd')], + 0, + timeT(), + timeT, + ); + t.editT([10, 10], [new CRDTTreeNode(posT(), 'p')], 0, timeT(), timeT); + t.editT( + [11, 11], + [new CRDTTreeNode(posT(), 'text', 'ef')], + 0, + timeT(), + timeT, + ); assert.deepEqual( t.toXML(), /*html*/ `

ab

cd

ef

`, ); - t.editT([9, 10], undefined, 0, timeT()); + t.editT([9, 10], undefined, 0, timeT(), timeT); assert.deepEqual( t.toXML(), /*html*/ `

ab

cd

ef

`, From bd5cd553aa107fc10ccc76eb9086bb92264cfaa0 Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Thu, 14 Dec 2023 17:07:58 +0900 Subject: [PATCH 17/48] Support concurrent insertion and splitting in Tree (#709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unlike text, which is split based on value, the number of nodes that can be created by splitting an element is not determined, so it was not possible to use ID by only changing the offset of the original NodeID. To solve this problem, a new TimeTicket is issued during Element Split to create a NodeID, but because of this, it was not possible to guarantee that the real parent of TreePos.Left was TreePos.Parent. TreePos.Parent is only used to represent the leftmost position by setting the values ​​of TreePos.Left and TreePos.Parent to be the same. This commit uses TreePos.Parent only to determine whether the pos is left-most and to directly use the parent of the actual node. --- src/document/crdt/tree.ts | 16 +++++++++++----- test/integration/tree_test.ts | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index fe66b5c3e..f32e8cb72 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -687,7 +687,13 @@ export class CRDTTree extends CRDTGCElement { const [parent, leftSibling] = pos.toTreeNodes(this); let leftNode = leftSibling; - // 02. Split text node if the left node is a text node. + // 02. Determine whether the position is left-most and the exact parent + // in the current tree. + const isLeftMost = parent === leftNode; + const realParent = + leftNode.parent && !isLeftMost ? leftNode.parent : parent; + + // 03. Split text node if the left node is a text node. if (leftNode.isText) { leftNode.split( this, @@ -695,11 +701,11 @@ export class CRDTTree extends CRDTGCElement { ); } - // 03. Find the appropriate left node. If some nodes are inserted at the + // 04. Find the appropriate left node. If some nodes are inserted at the // same position concurrently, then we need to find the appropriate left // node. This is similar to RGA. - const allChildren = parent.allChildren; - const index = parent === leftNode ? 0 : allChildren.indexOf(leftNode) + 1; + const allChildren = realParent.allChildren; + const index = isLeftMost ? 0 : allChildren.indexOf(leftNode) + 1; for (let i = index; i < parent.allChildren.length; i++) { const next = allChildren[i]; @@ -710,7 +716,7 @@ export class CRDTTree extends CRDTGCElement { leftNode = next; } - return [parent, leftNode]; + return [realParent, leftNode]; } /** diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index 6927d98dd..aa702a4c4 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -2774,7 +2774,7 @@ describe('testing edge cases', () => { }, task.name); }); - it.skip('Can concurrently split and insert into split node', async function ({ + it('Can concurrently split and insert into split node', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { From 736845410649a8e24cf0ac8a57bde209ac2666da Mon Sep 17 00:00:00 2001 From: Kevin Park Date: Fri, 15 Dec 2023 17:50:26 +0900 Subject: [PATCH 18/48] Migrate RPC to ConnectRPC (#698) With this support, we can resolve several issues: - Removes dependency with Envoy proxy to communicate with grpc-web - Reduces SDK bundle size by half bundle size of #434 - Standardizes API interfaces to powerful fetch API For more information about this migration, follow: yorkie#703 --------- Co-authored-by: Youngteac Hong --- CONTRIBUTING.md | 6 +- README.md | 14 - buf.gen.yaml | 12 + docker/docker-compose-ci.yml | 23 +- docker/docker-compose.yml | 24 +- docker/envoy-ci.yaml | 54 - docker/envoy.Dockerfile | 8 - docker/envoy.yaml | 59 - examples/nextjs-scheduler/README.md | 2 +- examples/profile-stack/README.md | 2 +- examples/react-tldraw/README.md | 2 +- .../src/hooks/useMultiplayerState.ts | 2 +- examples/react-todomvc/README.md | 2 +- examples/react-todomvc/src/App.tsx | 2 +- examples/simultaneous-cursors/README.md | 2 +- examples/vanilla-codemirror6/README.md | 2 +- examples/vanilla-codemirror6/src/main.ts | 2 +- examples/vanilla-quill/README.md | 2 +- examples/vanilla-quill/src/main.ts | 2 +- examples/vuejs-kanban/README.md | 2 +- package-lock.json | 238 +- package.json | 10 +- public/counter.html | 2 +- public/drawing.html | 2 +- public/index.html | 2 +- public/multi.html | 2 +- public/quill.html | 2 +- public/whiteboard.html | 2 +- src/api/converter.ts | 1054 +- src/api/yorkie/v1/resources.proto | 2 +- src/api/yorkie/v1/resources_pb.d.ts | 3275 ++-- src/api/yorkie/v1/resources_pb.js | 14216 +--------------- src/api/yorkie/v1/yorkie.proto | 4 +- src/api/yorkie/v1/yorkie_connect.d.ts | 106 + src/api/yorkie/v1/yorkie_connect.js | 111 + src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts | 113 - src/api/yorkie/v1/yorkie_grpc_web_pb.js | 564 - src/api/yorkie/v1/yorkie_pb.d.ts | 756 +- src/api/yorkie/v1/yorkie_pb.js | 3419 +--- src/client/attachment.ts | 28 +- src/client/auth_interceptor.ts | 63 +- src/client/client.ts | 560 +- src/client/metric_interceptor.ts | 36 +- test/integration/client_test.ts | 47 +- test/integration/integration_helper.ts | 2 +- test/integration/presence_test.ts | 77 +- 46 files changed, 4488 insertions(+), 20429 deletions(-) create mode 100644 buf.gen.yaml delete mode 100644 docker/envoy-ci.yaml delete mode 100644 docker/envoy.Dockerfile delete mode 100644 docker/envoy.yaml create mode 100644 src/api/yorkie/v1/yorkie_connect.d.ts create mode 100644 src/api/yorkie/v1/yorkie_connect.js delete mode 100644 src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts delete mode 100644 src/api/yorkie/v1/yorkie_grpc_web_pb.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fae44c4e7..b88557e22 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,9 +61,9 @@ $ npm run build:proto > Primary "source of truth" location of protobuf message is > in [yorkie](https://github.com/yorkie-team/yorkie/tree/main/api). We manage the messages in the repository. -### Testing yorkie-js-sdk with Envoy, Yorkie and MongoDB. +### Testing yorkie-js-sdk with Yorkie and MongoDB. -Start MongoDB, Yorkie and Envoy proxy in a terminal session. +Start MongoDB, Yorkie in a terminal session. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d @@ -112,7 +112,7 @@ $ npm run test {test file path} # e.g. npm run test integration/tree_test.ts ### Starting co-editing example with CodeMirror -Start MongoDB, Yorkie and Envoy proxy in a terminal session. +Start MongoDB and Yorkie in a terminal session. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/README.md b/README.md index e1e08b999..e22074834 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,6 @@ The Yorkie JavaScript SDK implements the client-side libraries. To get started using Yorkie JavaScript SDK, see: https://yorkie.dev/docs/js-sdk -## How yorkie-js-sdk works - -yorkie-js-sdk uses gRPC-web for communicating with Yorkie Server built on gRPC. - -``` - +--Browser--+ +--Envoy---------+ +--Yorkie-----+ - | | | | | | - | gRPC-web <- HTTP1.1 -> gRPC-web proxy <- HTTP2 -> gRPC server | - | | | | | | - +-----------+ +----------------+ +-------------+ -``` - -For more details: https://grpc.io/blog/state-of-grpc-web/ - ## Contributing See [CONTRIBUTING](CONTRIBUTING.md) for details on submitting patches and the contribution workflow. diff --git a/buf.gen.yaml b/buf.gen.yaml new file mode 100644 index 000000000..ea878f5e1 --- /dev/null +++ b/buf.gen.yaml @@ -0,0 +1,12 @@ +version: v1 +plugins: + - plugin: es + out: . + opt: + - target=js+dts + - js_import_style=legacy_commonjs + - plugin: connect-es + out: . + opt: + - target=js+dts + - js_import_style=legacy_commonjs diff --git a/docker/docker-compose-ci.yml b/docker/docker-compose-ci.yml index 0e733303d..5a852e492 100644 --- a/docker/docker-compose-ci.yml +++ b/docker/docker-compose-ci.yml @@ -1,31 +1,14 @@ version: '3.3' services: - envoy: - build: - context: ./ - dockerfile: ./envoy.Dockerfile - image: 'grpcweb:envoy' - container_name: 'envoy' - restart: always - ports: - - '8080:8080' - - '9901:9901' - command: ['/etc/envoy/envoy-ci.yaml'] - depends_on: - - yorkie yorkie: image: 'yorkieteam/yorkie:latest' container_name: 'yorkie' - command: [ - 'server', - '--mongo-connection-uri', - 'mongodb://mongo:27017', - ] + command: ['server', '--mongo-connection-uri', 'mongodb://mongo:27017'] restart: always ports: - - '11101:11101' - - '11102:11102' + - '8080:8080' + - '8081:8081' depends_on: - mongo mongo: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index adc68d021..c03eda524 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,31 +1,11 @@ version: '3.3' services: - envoy: - build: - context: ./ - dockerfile: ./envoy.Dockerfile - image: 'grpcweb:envoy' - container_name: 'envoy' - restart: always - ports: - - '8080:8080' - - '9901:9901' - command: ['/etc/envoy/envoy.yaml'] - depends_on: - - yorkie - # If you're using Mac or Windows, this special domain name("host.docker.internal" which makes containers able to connect to the host) - # is supported by default. - # But if you're using Linux and want an envoy container to communicate with the host, - # it may help to define "host.docker.internal" in extra_hosts. - # (Actually, other hostnames are available, but in that case you should update clusters[].host configurations of envoy.yaml) - extra_hosts: - - 'host.docker.internal:host-gateway' yorkie: image: 'yorkieteam/yorkie:latest' container_name: 'yorkie' command: ['server', '--enable-pprof'] restart: always ports: - - '11101:11101' - - '11102:11102' + - '8080:8080' + - '8081:8081' diff --git a/docker/envoy-ci.yaml b/docker/envoy-ci.yaml deleted file mode 100644 index 416e72a25..000000000 --- a/docker/envoy-ci.yaml +++ /dev/null @@ -1,54 +0,0 @@ -admin: - access_log_path: /tmp/admin_access.log - address: - socket_address: { address: 0.0.0.0, port_value: 9901 } - -static_resources: - listeners: - - name: yorkie_rpc_listener - address: - socket_address: { address: 0.0.0.0, port_value: 8080 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: local_service - domains: ["*"] - routes: - - match: { prefix: "/" } - route: - cluster: yorkie_rpc_service - # https://github.com/grpc/grpc-web/issues/361 - max_stream_duration: - grpc_timeout_header_max: 0s - cors: - allow_origin_string_match: - - prefix: "*" - allow_methods: GET, PUT, DELETE, POST, OPTIONS - allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-api-key,x-shard-key,x-user-agent,x-grpc-web,grpc-timeout,authorization,x-yorkie-user-agent - max_age: "1728000" - expose_headers: custom-header-1,grpc-status,grpc-message - http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router - clusters: - - name: yorkie_rpc_service - connect_timeout: 0.25s - type: logical_dns - http2_protocol_options: {} - lb_policy: round_robin - load_assignment: - cluster_name: yorkie_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: yorkie - port_value: 11101 diff --git a/docker/envoy.Dockerfile b/docker/envoy.Dockerfile deleted file mode 100644 index 60b660b76..000000000 --- a/docker/envoy.Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM envoyproxy/envoy:v1.19.0 - -COPY ./envoy.yaml /etc/envoy/envoy.yaml -COPY ./envoy-ci.yaml /etc/envoy/envoy-ci.yaml - -ENTRYPOINT ["/usr/local/bin/envoy", "-c"] - -CMD /etc/envoy/envoy.yaml diff --git a/docker/envoy.yaml b/docker/envoy.yaml deleted file mode 100644 index 69b92bcc5..000000000 --- a/docker/envoy.yaml +++ /dev/null @@ -1,59 +0,0 @@ -admin: - access_log_path: /tmp/admin_access.log - address: - socket_address: { address: 0.0.0.0, port_value: 9901 } - -static_resources: - listeners: - - name: yorkie_rpc_listener - address: - socket_address: { address: 0.0.0.0, port_value: 8080 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress_http - route_config: - name: local_route - virtual_hosts: - - name: local_service - domains: ["*"] - routes: - - match: { prefix: "/" } - route: - cluster: yorkie_rpc_service - # https://github.com/grpc/grpc-web/issues/361 - max_stream_duration: - grpc_timeout_header_max: 0s - cors: - allow_origin_string_match: - - prefix: "*" - allow_methods: GET, PUT, DELETE, POST, OPTIONS - allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-api-key,x-shard-key,x-user-agent,x-grpc-web,grpc-timeout,authorization,x-yorkie-user-agent - max_age: "1728000" - expose_headers: custom-header-1,grpc-status,grpc-message - http_filters: - - name: envoy.filters.http.grpc_web - - name: envoy.filters.http.cors - - name: envoy.filters.http.router - clusters: - - name: yorkie_rpc_service - connect_timeout: 0.25s - type: logical_dns - http2_protocol_options: {} - lb_policy: round_robin - # Input the address which envoy can connect to as a yorkie server. - # When you want envoy container to communicate with your host machine, you should set as the following - # - Windows/Mac: Input host.docker.internal - # - Linux: an IP address of the host machine or docker-0 interface or some addresses defined in extra hosts of docker-compose.yml - # you can simply use the yorkie container name(e.g. yorkie) in docker-compose whatever your OS is. - load_assignment: - cluster_name: yorkie_cluster - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: host.docker.internal - port_value: 11101 diff --git a/examples/nextjs-scheduler/README.md b/examples/nextjs-scheduler/README.md index a89828187..90e17186a 100644 --- a/examples/nextjs-scheduler/README.md +++ b/examples/nextjs-scheduler/README.md @@ -10,7 +10,7 @@ ## How to run demo -At project root, run below command to start Yorkie server and Envoy proxy. +At project root, run below command to start Yorkie server. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/profile-stack/README.md b/examples/profile-stack/README.md index 5171a5df0..1c3540ffc 100644 --- a/examples/profile-stack/README.md +++ b/examples/profile-stack/README.md @@ -10,7 +10,7 @@ ## How to run demo -At project root, run below command to start Yorkie and Envoy proxy. +At project root, run below command to start Yorkie. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/react-tldraw/README.md b/examples/react-tldraw/README.md index 7ef547b9f..8065e762e 100644 --- a/examples/react-tldraw/README.md +++ b/examples/react-tldraw/README.md @@ -10,7 +10,7 @@ ## How to run demo -At project root, run below command to start Yorkie server and Envoy proxy. +At project root, run below command to start Yorkie server. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/react-tldraw/src/hooks/useMultiplayerState.ts b/examples/react-tldraw/src/hooks/useMultiplayerState.ts index db489d333..4329255ae 100644 --- a/examples/react-tldraw/src/hooks/useMultiplayerState.ts +++ b/examples/react-tldraw/src/hooks/useMultiplayerState.ts @@ -192,7 +192,7 @@ export function useMultiplayerState(roomId: string) { // Setup the document's storage and subscriptions async function setupDocument() { try { - // 01. Create client with RPCAddr(envoy) and options with apiKey if provided. + // 01. Create client with RPCAddr and options with apiKey if provided. // Then activate client. const options: Options = { apiKey: import.meta.env.VITE_YORKIE_API_KEY, diff --git a/examples/react-todomvc/README.md b/examples/react-todomvc/README.md index 85583e7fd..2dd89d93f 100644 --- a/examples/react-todomvc/README.md +++ b/examples/react-todomvc/README.md @@ -10,7 +10,7 @@ ## How to run demo -At project root, run below command to start Yorkie server and Envoy proxy. +At project root, run below command to start Yorkie server. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/react-todomvc/src/App.tsx b/examples/react-todomvc/src/App.tsx index 6b8428b7b..64df6b0a3 100644 --- a/examples/react-todomvc/src/App.tsx +++ b/examples/react-todomvc/src/App.tsx @@ -118,7 +118,7 @@ export default function App() { doc: Document<{ todos: JSONArray }>, callback: (todos: any) => void, ) { - // 01. create client with RPCAddr(envoy) then activate it. + // 01. create client with RPCAddr then activate it. await client.activate(); // 02. attach the document into the client. diff --git a/examples/simultaneous-cursors/README.md b/examples/simultaneous-cursors/README.md index c07d50a5a..cb8264b10 100644 --- a/examples/simultaneous-cursors/README.md +++ b/examples/simultaneous-cursors/README.md @@ -41,7 +41,7 @@ Install dependencies $ npm install ``` -At project root, run below command to start Yorkie and Envoy proxy. +At project root, run below command to start Yorkie server. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/vanilla-codemirror6/README.md b/examples/vanilla-codemirror6/README.md index 64eccc0ce..e1f1c74db 100644 --- a/examples/vanilla-codemirror6/README.md +++ b/examples/vanilla-codemirror6/README.md @@ -10,7 +10,7 @@ ## How to run demo -At project root, run below command to start Yorkie and Envoy proxy. +At project root, run below command to start Yorkie. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/vanilla-codemirror6/src/main.ts b/examples/vanilla-codemirror6/src/main.ts index 8f043b1bc..a45a2ceac 100644 --- a/examples/vanilla-codemirror6/src/main.ts +++ b/examples/vanilla-codemirror6/src/main.ts @@ -20,7 +20,7 @@ const documentTextElem = document.getElementById('document-text')!; const networkStatusElem = document.getElementById('network-status')!; async function main() { - // 01. create client with RPCAddr(envoy) then activate it. + // 01. create client with RPCAddr then activate it. const client = new yorkie.Client(import.meta.env.VITE_YORKIE_API_ADDR, { apiKey: import.meta.env.VITE_YORKIE_API_KEY, }); diff --git a/examples/vanilla-quill/README.md b/examples/vanilla-quill/README.md index 6e9d5b54b..424d484f9 100644 --- a/examples/vanilla-quill/README.md +++ b/examples/vanilla-quill/README.md @@ -41,7 +41,7 @@ Install dependencies $ npm install ``` -At project root, run below command to start Yorkie and Envoy proxy. +At project root, run below command to start Yorkie. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/examples/vanilla-quill/src/main.ts b/examples/vanilla-quill/src/main.ts index d64f412b3..15bd03272 100644 --- a/examples/vanilla-quill/src/main.ts +++ b/examples/vanilla-quill/src/main.ts @@ -41,7 +41,7 @@ function toDeltaOperation( } async function main() { - // 01-1. create client with RPCAddr(envoy) then activate it. + // 01-1. create client with RPCAddr then activate it. const client = new yorkie.Client(import.meta.env.VITE_YORKIE_API_ADDR, { apiKey: import.meta.env.VITE_YORKIE_API_KEY, }); diff --git a/examples/vuejs-kanban/README.md b/examples/vuejs-kanban/README.md index 6e2a6ba18..9f42dcca7 100644 --- a/examples/vuejs-kanban/README.md +++ b/examples/vuejs-kanban/README.md @@ -10,7 +10,7 @@ ## How to run demo -At project root, run below command to start Yorkie and Envoy proxy. +At project root, run below command to start Yorkie server. ```bash $ docker-compose -f docker/docker-compose.yml up --build -d diff --git a/package-lock.json b/package-lock.json index df80318ee..920a39146 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,27 @@ { "name": "yorkie-js-sdk", - "version": "0.4.9", + "version": "0.4.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "yorkie-js-sdk", - "version": "0.4.9", + "version": "0.4.10", "license": "Apache-2.0", "workspaces": [ "examples/*", "tools/*" ], "dependencies": { - "google-protobuf": "^3.19.4", - "grpc-web": "^1.3.1", + "@bufbuild/protobuf": "^1.6.0", + "@connectrpc/connect": "^1.2.0", + "@connectrpc/connect-web": "^1.2.0", "long": "^5.2.0" }, "devDependencies": { + "@bufbuild/buf": "^1.28.1", + "@bufbuild/protoc-gen-es": "^1.6.0", + "@connectrpc/protoc-gen-connect-es": "^1.2.0", "@microsoft/api-documenter": "^7.15.1", "@microsoft/api-extractor": "^7.19.4", "@types/benchmark": "^2.1.1", @@ -1024,6 +1028,178 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@bufbuild/buf": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.28.1.tgz", + "integrity": "sha512-WRDagrf0uBjfV9s5eyrSPJDcdI4A5Q7JMCA4aMrHRR8fo/TTjniDBjJprszhaguqsDkn/LS4QIu92HVFZCrl9A==", + "dev": true, + "hasInstallScript": true, + "bin": { + "buf": "bin/buf", + "protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking", + "protoc-gen-buf-lint": "bin/protoc-gen-buf-lint" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@bufbuild/buf-darwin-arm64": "1.28.1", + "@bufbuild/buf-darwin-x64": "1.28.1", + "@bufbuild/buf-linux-aarch64": "1.28.1", + "@bufbuild/buf-linux-x64": "1.28.1", + "@bufbuild/buf-win32-arm64": "1.28.1", + "@bufbuild/buf-win32-x64": "1.28.1" + } + }, + "node_modules/@bufbuild/buf-darwin-arm64": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.28.1.tgz", + "integrity": "sha512-nAyvwKkcd8qQTExCZo5MtSRhXLK7e3vzKFKHjXfkveRakSUST2HFlFZAHfErZimN4wBrPTN0V0hNRU8PPjkMpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-darwin-x64": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.28.1.tgz", + "integrity": "sha512-b0eT3xd3vX5a5lWAbo5h7FPuf9MsOJI4I39qs4TZnrlZ8BOuPfqzwzijiFf9UCwaX2vR1NQXexIoQ80Ci+fCHw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-linux-aarch64": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.28.1.tgz", + "integrity": "sha512-p5h9bZCVLMh8No9/7k7ulXzsFx5P7Lu6DiUMjSJ6aBXPMYo6Xl7r/6L2cQkpsZ53HMtIxCgMYS9a7zoS4K8wIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-linux-x64": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.28.1.tgz", + "integrity": "sha512-fVJ3DiRigIso06jgEl+JNp59Y5t2pxDHd10d3SA4r+14sXbZ2J7Gy/wBqVXPry4x/jW567KKlvmhg7M5ZBgCQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-win32-arm64": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.28.1.tgz", + "integrity": "sha512-KJiRJpugQRK/jXC46Xjlb68UydWhCZj2jHdWLIwNtgXd1WTJ3LngChZV7Y6pPK08pwBAVz0JYeVbD5IlTCD4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/buf-win32-x64": { + "version": "1.28.1", + "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.28.1.tgz", + "integrity": "sha512-vMnc+7OVCkmlRWQsgYHgUqiBPRIjD8XeoRyApJ07YZzGs7DkRH4LhvmacJbLd3wORylbn6gLz3pQa8J/M61mzg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.6.0.tgz", + "integrity": "sha512-hp19vSFgNw3wBBcVBx5qo5pufCqjaJ0Cfk5H/pfjNOfNWU+4/w0QVOmfAOZNRrNWRrVuaJWxcN8P2vhOkkzbBQ==" + }, + "node_modules/@bufbuild/protoc-gen-es": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protoc-gen-es/-/protoc-gen-es-1.6.0.tgz", + "integrity": "sha512-m0akOPWeD5UBfGdZyudrbnmdjI8l/ZHlP8TyEIcj7qMCR4kh68tMtGvrjRzj5ynIpavrr6G7P06XP9F9f2MDRw==", + "dev": true, + "dependencies": { + "@bufbuild/protobuf": "^1.6.0", + "@bufbuild/protoplugin": "1.6.0" + }, + "bin": { + "protoc-gen-es": "bin/protoc-gen-es" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@bufbuild/protobuf": "1.6.0" + }, + "peerDependenciesMeta": { + "@bufbuild/protobuf": { + "optional": true + } + } + }, + "node_modules/@bufbuild/protoplugin": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protoplugin/-/protoplugin-1.6.0.tgz", + "integrity": "sha512-o53ZsvojHQkAPoC9v5sJifY2OfXdRU8DO3QpPoJ+QuvYcfB9Zb3DZkNMQRyfEbF4TVYiaQ0mZzZl1mESDdyCxA==", + "dev": true, + "dependencies": { + "@bufbuild/protobuf": "1.6.0", + "@typescript/vfs": "^1.4.0", + "typescript": "4.5.2" + } + }, + "node_modules/@bufbuild/protoplugin/node_modules/typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/@codemirror/autocomplete": { "version": "6.3.4", "license": "MIT", @@ -1324,6 +1500,51 @@ "w3c-keyname": "^2.2.4" } }, + "node_modules/@connectrpc/connect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-1.2.0.tgz", + "integrity": "sha512-kHF30xAlXF2Y7S1I7XN/D3psKLfjxitgNRmF093KNP+cE9yAnqDAGop6aby3Z5k4XQw2ebjeX4E41db7R3FzaQ==", + "peerDependencies": { + "@bufbuild/protobuf": "^1.4.2" + } + }, + "node_modules/@connectrpc/connect-web": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-1.2.0.tgz", + "integrity": "sha512-vjFKTP/AzSnC8JvkGKRgpggZIB0v+Lv7U+/Tb/pRNGZI0WSElhGDXWgIn3xfcSNQWi079m45c5MlikszzIRsYg==", + "peerDependencies": { + "@bufbuild/protobuf": "^1.4.2", + "@connectrpc/connect": "1.2.0" + } + }, + "node_modules/@connectrpc/protoc-gen-connect-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/protoc-gen-connect-es/-/protoc-gen-connect-es-1.2.0.tgz", + "integrity": "sha512-VJ50wqjLJ4Thk6nOgARALCny+AMxHDS3fxAVEV1oveVXRbrCl5pb8ge/erKYyxuLKyBYe/I00MFa+ns6C3nN7g==", + "dev": true, + "dependencies": { + "@bufbuild/protobuf": "^1.6.0", + "@bufbuild/protoplugin": "^1.6.0" + }, + "bin": { + "protoc-gen-connect-es": "bin/protoc-gen-connect-es" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@bufbuild/protoc-gen-es": "^1.6.0", + "@connectrpc/connect": "1.2.0" + }, + "peerDependenciesMeta": { + "@bufbuild/protoc-gen-es": { + "optional": true + }, + "@connectrpc/connect": { + "optional": true + } + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "dev": true, @@ -3810,6 +4031,15 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript/vfs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.5.0.tgz", + "integrity": "sha512-AJS307bPgbsZZ9ggCT3wwpg3VbTKMFNHfaY/uF0ahSkYYrPF2dSSKDNIDIQAHm9qJqbLvCsSJH7yN4Vs/CsMMg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1" + } + }, "node_modules/@use-gesture/core": { "version": "10.2.23", "license": "MIT" diff --git a/package.json b/package.json index 057f239f5..c468833ee 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ ], "scripts": { "build": "webpack --config ./config/webpack.config.js && npm run api-report && npm run prune", - "build:proto": "protoc -I=./src/api --js_out=import_style=commonjs:./src/api --grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:./src/api ./src/api/yorkie/v1/*.proto", + "build:proto": "npx buf generate", "build:docs": "npm run predoc && api-documenter markdown --input temp --output docs", "build:examples": "npm run build --workspace examples", "build:create-yorkie-app": "npm run build --workspace create-yorkie-app", @@ -46,6 +46,9 @@ }, "homepage": "https://github.com/yorkie-team/yorkie-js-sdk#readme", "devDependencies": { + "@bufbuild/buf": "^1.28.1", + "@bufbuild/protoc-gen-es": "^1.6.0", + "@connectrpc/protoc-gen-connect-es": "^1.2.0", "@microsoft/api-documenter": "^7.15.1", "@microsoft/api-extractor": "^7.19.4", "@types/benchmark": "^2.1.1", @@ -85,8 +88,9 @@ "yargs": "^17.0.1" }, "dependencies": { - "google-protobuf": "^3.19.4", - "grpc-web": "^1.3.1", + "@bufbuild/protobuf": "^1.6.0", + "@connectrpc/connect": "^1.2.0", + "@connectrpc/connect-web": "^1.2.0", "long": "^5.2.0" }, "husky": { diff --git a/public/counter.html b/public/counter.html index f53b7d6c5..2670b6d52 100644 --- a/public/counter.html +++ b/public/counter.html @@ -36,7 +36,7 @@ async function main() { try { - // 01. create client with RPCAddr(envoy) then activate it. + // 01. create client with RPCAddr then activate it. const client = new yorkie.Client('http://localhost:8080'); client.subscribe(network.statusListener(statusHolder)); await client.activate(); diff --git a/public/drawing.html b/public/drawing.html index f526ee09d..e12a30736 100644 --- a/public/drawing.html +++ b/public/drawing.html @@ -37,7 +37,7 @@ async function main() { try { - // 01. create client with RPCAddr(envoy) then activate it. + // 01. create client with RPCAddr then activate it. const client = new yorkie.Client('http://localhost:8080', { syncLoopDuration: 0, reconnectStreamDelay: 1000, diff --git a/public/index.html b/public/index.html index 965c83a71..f74075eba 100644 --- a/public/index.html +++ b/public/index.html @@ -323,7 +323,7 @@

}); devtool.setCodeMirror(codemirror); - // 02-1. create client with RPCAddr(envoy). + // 02-1. create client with RPCAddr. const client = new yorkie.Client('http://localhost:8080'); // 02-2. subscribe client event. client.subscribe(network.statusListener(statusHolder)); diff --git a/public/multi.html b/public/multi.html index 40a57cfab..c6fc3912a 100644 --- a/public/multi.html +++ b/public/multi.html @@ -78,7 +78,7 @@

yorkie document

async function main() { try { - // 01-1. create client with RPCAddr(envoy). + // 01-1. create client with RPCAddr. const client = new yorkie.Client('http://localhost:8080'); // 01-2. subscribe client event. client.subscribe(network.statusListener(statusHolder)); diff --git a/public/quill.html b/public/quill.html index 0e70728f4..314fb4d1b 100644 --- a/public/quill.html +++ b/public/quill.html @@ -64,7 +64,7 @@ async function main() { try { - // 01. create client with RPCAddr(envoy) then activate it. + // 01. create client with RPCAddr then activate it. const client = new yorkie.Client('http://localhost:8080'); await client.activate(); client.subscribe(network.statusListener(networkStatusElem)); diff --git a/public/whiteboard.html b/public/whiteboard.html index baaee3c89..71ebed24d 100644 --- a/public/whiteboard.html +++ b/public/whiteboard.html @@ -253,7 +253,7 @@

async function main() { try { - // 01. create client with RPCAddr(envoy) then activate it. + // 01. create client with RPCAddr then activate it. const client = new yorkie.Client('http://localhost:8080'); client.subscribe(network.statusListener(statusHolder)); await client.activate(); diff --git a/src/api/converter.ts b/src/api/converter.ts index 3ee828f1e..b0fab299f 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -15,7 +15,6 @@ */ import Long from 'long'; -import * as jspb from 'google-protobuf'; import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; import { Indexable } from '@yorkie-js-sdk/src/document/document'; import { @@ -79,6 +78,22 @@ import { TreePos as PbTreePos, TreeNodeID as PbTreeNodeID, ValueType as PbValueType, + JSONElement_Tree as PbJSONElement_Tree, + JSONElement_Text as PbJSONElement_Text, + JSONElement_Primitive as PbJSONElement_Primitive, + JSONElement_Counter as PbJSONElement_Counter, + JSONElement_JSONObject as PbJSONElement_JSONObject, + JSONElement_JSONArray as PbJSONElement_JSONArray, + PresenceChange_ChangeType as PbPresenceChange_ChangeType, + Operation_Set as PbOperation_Set, + Operation_Add as PbOperation_Add, + Operation_Move as PbOperation_Move, + Operation_Remove as PbOperation_Remove, + Operation_Edit as PbOperation_Edit, + Operation_Style as PbOperation_Style, + Operation_Increase as PbOperation_Increase, + Operation_TreeEdit as PbOperation_TreeEdit, + Operation_TreeStyle as PbOperation_TreeStyle, } from '@yorkie-js-sdk/src/api/yorkie/v1/resources_pb'; import { IncreaseOperation } from '@yorkie-js-sdk/src/document/operation/increase_operation'; import { @@ -99,9 +114,9 @@ import { RHT } from '../document/crdt/rht'; */ function toPresence(presence: Indexable): PbPresence { const pbPresence = new PbPresence(); - const pbDataMap = pbPresence.getDataMap(); + const pbDataMap = pbPresence.data; for (const [key, value] of Object.entries(presence)) { - pbDataMap.set(key, JSON.stringify(value)); + pbDataMap[key] = JSON.stringify(value); } return pbPresence; } @@ -112,37 +127,40 @@ function toPresence(presence: Indexable): PbPresence { function toPresenceChange( presenceChange: PresenceChange, ): PbPresenceChange { - const pbPresenceChange = new PbPresenceChange(); - if (presenceChange.type === PresenceChangeType.Put) { - pbPresenceChange.setType(PbPresenceChange.ChangeType.CHANGE_TYPE_PUT); - pbPresenceChange.setPresence(toPresence(presenceChange.presence)); - } else if (presenceChange.type === PresenceChangeType.Clear) { - pbPresenceChange.setType(PbPresenceChange.ChangeType.CHANGE_TYPE_CLEAR); + return new PbPresenceChange({ + type: PbPresenceChange_ChangeType.PUT, + presence: toPresence(presenceChange.presence), + }); + } + if (presenceChange.type === PresenceChangeType.Clear) { + return new PbPresenceChange({ + type: PbPresenceChange_ChangeType.CLEAR, + }); } - return pbPresenceChange; + throw new YorkieError(Code.Unimplemented, `unimplemented type`); } /** * `toCheckpoint` converts the given model to Protobuf format. */ function toCheckpoint(checkpoint: Checkpoint): PbCheckpoint { - const pbCheckpoint = new PbCheckpoint(); - pbCheckpoint.setServerSeq(checkpoint.getServerSeqAsString()); - pbCheckpoint.setClientSeq(checkpoint.getClientSeq()); - return pbCheckpoint; + return new PbCheckpoint({ + serverSeq: checkpoint.getServerSeqAsString(), + clientSeq: checkpoint.getClientSeq(), + }); } /** * `toChangeID` converts the given model to Protobuf format. */ function toChangeID(changeID: ChangeID): PbChangeID { - const pbChangeID = new PbChangeID(); - pbChangeID.setClientSeq(changeID.getClientSeq()); - pbChangeID.setLamport(changeID.getLamportAsString()); - pbChangeID.setActorId(toUint8Array(changeID.getActorID()!)); - return pbChangeID; + return new PbChangeID({ + clientSeq: changeID.getClientSeq(), + lamport: changeID.getLamportAsString(), + actorId: toUint8Array(changeID.getActorID()!), + }); } /** @@ -153,11 +171,11 @@ function toTimeTicket(ticket?: TimeTicket): PbTimeTicket | undefined { return; } - const pbTimeTicket = new PbTimeTicket(); - pbTimeTicket.setLamport(ticket.getLamportAsString()); - pbTimeTicket.setDelimiter(ticket.getDelimiter()); - pbTimeTicket.setActorId(toUint8Array(ticket.getActorID()!)); - return pbTimeTicket; + return new PbTimeTicket({ + lamport: ticket.getLamportAsString(), + delimiter: ticket.getDelimiter(), + actorId: toUint8Array(ticket.getActorID()!), + }); } /** @@ -166,21 +184,21 @@ function toTimeTicket(ticket?: TimeTicket): PbTimeTicket | undefined { function toValueType(valueType: PrimitiveType): PbValueType { switch (valueType) { case PrimitiveType.Null: - return PbValueType.VALUE_TYPE_NULL; + return PbValueType.NULL; case PrimitiveType.Boolean: - return PbValueType.VALUE_TYPE_BOOLEAN; + return PbValueType.BOOLEAN; case PrimitiveType.Integer: - return PbValueType.VALUE_TYPE_INTEGER; + return PbValueType.INTEGER; case PrimitiveType.Long: - return PbValueType.VALUE_TYPE_LONG; + return PbValueType.LONG; case PrimitiveType.Double: - return PbValueType.VALUE_TYPE_DOUBLE; + return PbValueType.DOUBLE; case PrimitiveType.String: - return PbValueType.VALUE_TYPE_STRING; + return PbValueType.STRING; case PrimitiveType.Bytes: - return PbValueType.VALUE_TYPE_BYTES; + return PbValueType.BYTES; case PrimitiveType.Date: - return PbValueType.VALUE_TYPE_DATE; + return PbValueType.DATE; default: throw new YorkieError(Code.Unsupported, `unsupported type: ${valueType}`); } @@ -192,9 +210,9 @@ function toValueType(valueType: PrimitiveType): PbValueType { function toCounterType(valueType: CounterType): PbValueType { switch (valueType) { case CounterType.IntegerCnt: - return PbValueType.VALUE_TYPE_INTEGER_CNT; + return PbValueType.INTEGER_CNT; case CounterType.LongCnt: - return PbValueType.VALUE_TYPE_LONG_CNT; + return PbValueType.LONG_CNT; default: throw new YorkieError(Code.Unsupported, `unsupported type: ${valueType}`); } @@ -204,79 +222,90 @@ function toCounterType(valueType: CounterType): PbValueType { * `toElementSimple` converts the given model to Protobuf format. */ function toElementSimple(element: CRDTElement): PbJSONElementSimple { - const pbElementSimple = new PbJSONElementSimple(); if (element instanceof CRDTObject) { - pbElementSimple.setType(PbValueType.VALUE_TYPE_JSON_OBJECT); - pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); - pbElementSimple.setValue(objectToBytes(element)); - } else if (element instanceof CRDTArray) { - pbElementSimple.setType(PbValueType.VALUE_TYPE_JSON_ARRAY); - pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); - pbElementSimple.setValue(arrayToBytes(element)); - } else if (element instanceof CRDTText) { - pbElementSimple.setType(PbValueType.VALUE_TYPE_TEXT); - pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); - } else if (element instanceof Primitive) { - const primitive = element as Primitive; - pbElementSimple.setType(toValueType(primitive.getType())); - pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); - pbElementSimple.setValue(element.toBytes()); - } else if (element instanceof CRDTCounter) { - const counter = element as CRDTCounter; - pbElementSimple.setType(toCounterType(counter.getType())); - pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); - pbElementSimple.setValue(element.toBytes()); - } else if (element instanceof CRDTTree) { - const tree = element as CRDTTree; - pbElementSimple.setType(PbValueType.VALUE_TYPE_TREE); - pbElementSimple.setCreatedAt(toTimeTicket(element.getCreatedAt())); - pbElementSimple.setValue(treeToBytes(tree)); - } else { - throw new YorkieError(Code.Unimplemented, `unimplemented element`); + return new PbJSONElementSimple({ + type: PbValueType.JSON_OBJECT, + createdAt: toTimeTicket(element.getCreatedAt()), + value: objectToBytes(element), + }); + } + if (element instanceof CRDTArray) { + return new PbJSONElementSimple({ + type: PbValueType.JSON_ARRAY, + createdAt: toTimeTicket(element.getCreatedAt()), + value: arrayToBytes(element), + }); + } + if (element instanceof CRDTText) { + return new PbJSONElementSimple({ + type: PbValueType.TEXT, + createdAt: toTimeTicket(element.getCreatedAt()), + }); + } + if (element instanceof Primitive) { + return new PbJSONElementSimple({ + type: toValueType(element.getType()), + createdAt: toTimeTicket(element.getCreatedAt()), + value: element.toBytes(), + }); + } + if (element instanceof CRDTCounter) { + return new PbJSONElementSimple({ + type: toCounterType(element.getType()), + createdAt: toTimeTicket(element.getCreatedAt()), + value: element.toBytes(), + }); + } + if (element instanceof CRDTTree) { + return new PbJSONElementSimple({ + type: PbValueType.TREE, + createdAt: toTimeTicket(element.getCreatedAt()), + value: treeToBytes(element), + }); } - return pbElementSimple; + throw new YorkieError(Code.Unimplemented, `unimplemented element`); } /** * `toTextNodeID` converts the given model to Protobuf format. */ function toTextNodeID(id: RGATreeSplitNodeID): PbTextNodeID { - const pbTextNodeID = new PbTextNodeID(); - pbTextNodeID.setCreatedAt(toTimeTicket(id.getCreatedAt())); - pbTextNodeID.setOffset(id.getOffset()); - return pbTextNodeID; + return new PbTextNodeID({ + createdAt: toTimeTicket(id.getCreatedAt()), + offset: id.getOffset(), + }); } /** * `toTextNodePos` converts the given model to Protobuf format. */ function toTextNodePos(pos: RGATreeSplitPos): PbTextNodePos { - const pbTextNodePos = new PbTextNodePos(); - pbTextNodePos.setCreatedAt(toTimeTicket(pos.getID().getCreatedAt())); - pbTextNodePos.setOffset(pos.getID().getOffset()); - pbTextNodePos.setRelativeOffset(pos.getRelativeOffset()); - return pbTextNodePos; + return new PbTextNodePos({ + createdAt: toTimeTicket(pos.getID().getCreatedAt()), + offset: pos.getID().getOffset(), + relativeOffset: pos.getRelativeOffset(), + }); } /** * `toTreePos` converts the given model to Protobuf format. */ function toTreePos(pos: CRDTTreePos): PbTreePos { - const pbTreePos = new PbTreePos(); - pbTreePos.setParentId(toTreeNodeID(pos.getParentID())); - pbTreePos.setLeftSiblingId(toTreeNodeID(pos.getLeftSiblingID())); - return pbTreePos; + return new PbTreePos({ + parentId: toTreeNodeID(pos.getParentID()), + leftSiblingId: toTreeNodeID(pos.getLeftSiblingID()), + }); } /** * `toTreeNodeID` converts the given model to Protobuf format. */ function toTreeNodeID(treeNodeID: CRDTTreeNodeID): PbTreeNodeID { - const pbTreeNodeID = new PbTreeNodeID(); - pbTreeNodeID.setCreatedAt(toTimeTicket(treeNodeID.getCreatedAt())); - pbTreeNodeID.setOffset(treeNodeID.getOffset()); - return pbTreeNodeID; + return new PbTreeNodeID({ + createdAt: toTimeTicket(treeNodeID.getCreatedAt()), + offset: treeNodeID.getOffset(), + }); } /** @@ -287,141 +316,145 @@ function toOperation(operation: Operation): PbOperation { if (operation instanceof SetOperation) { const setOperation = operation as SetOperation; - const pbSetOperation = new PbOperation.Set(); - pbSetOperation.setParentCreatedAt( - toTimeTicket(setOperation.getParentCreatedAt()), + const pbSetOperation = new PbOperation_Set(); + pbSetOperation.parentCreatedAt = toTimeTicket( + setOperation.getParentCreatedAt(), ); - pbSetOperation.setKey(setOperation.getKey()); - pbSetOperation.setValue(toElementSimple(setOperation.getValue())); - pbSetOperation.setExecutedAt(toTimeTicket(setOperation.getExecutedAt())); - pbOperation.setSet(pbSetOperation); + pbSetOperation.key = setOperation.getKey(); + pbSetOperation.value = toElementSimple(setOperation.getValue()); + pbSetOperation.executedAt = toTimeTicket(setOperation.getExecutedAt()); + pbOperation.body.case = 'set'; + pbOperation.body.value = pbSetOperation; } else if (operation instanceof AddOperation) { const addOperation = operation as AddOperation; - const pbAddOperation = new PbOperation.Add(); - pbAddOperation.setParentCreatedAt( - toTimeTicket(addOperation.getParentCreatedAt()), + const pbAddOperation = new PbOperation_Add(); + pbAddOperation.parentCreatedAt = toTimeTicket( + addOperation.getParentCreatedAt(), ); - pbAddOperation.setPrevCreatedAt( - toTimeTicket(addOperation.getPrevCreatedAt()), + pbAddOperation.prevCreatedAt = toTimeTicket( + addOperation.getPrevCreatedAt(), ); - pbAddOperation.setValue(toElementSimple(addOperation.getValue())); - pbAddOperation.setExecutedAt(toTimeTicket(addOperation.getExecutedAt())); - pbOperation.setAdd(pbAddOperation); + pbAddOperation.value = toElementSimple(addOperation.getValue()); + pbAddOperation.executedAt = toTimeTicket(addOperation.getExecutedAt()); + pbOperation.body.case = 'add'; + pbOperation.body.value = pbAddOperation; } else if (operation instanceof MoveOperation) { const moveOperation = operation as MoveOperation; - const pbMoveOperation = new PbOperation.Move(); - pbMoveOperation.setParentCreatedAt( - toTimeTicket(moveOperation.getParentCreatedAt()), + const pbMoveOperation = new PbOperation_Move(); + pbMoveOperation.parentCreatedAt = toTimeTicket( + moveOperation.getParentCreatedAt(), ); - pbMoveOperation.setPrevCreatedAt( - toTimeTicket(moveOperation.getPrevCreatedAt()), + pbMoveOperation.prevCreatedAt = toTimeTicket( + moveOperation.getPrevCreatedAt(), ); - pbMoveOperation.setCreatedAt(toTimeTicket(moveOperation.getCreatedAt())); - pbMoveOperation.setExecutedAt(toTimeTicket(moveOperation.getExecutedAt())); - pbOperation.setMove(pbMoveOperation); + pbMoveOperation.createdAt = toTimeTicket(moveOperation.getCreatedAt()); + pbMoveOperation.executedAt = toTimeTicket(moveOperation.getExecutedAt()); + pbOperation.body.case = 'move'; + pbOperation.body.value = pbMoveOperation; } else if (operation instanceof RemoveOperation) { const removeOperation = operation as RemoveOperation; - const pbRemoveOperation = new PbOperation.Remove(); - pbRemoveOperation.setParentCreatedAt( - toTimeTicket(removeOperation.getParentCreatedAt()), - ); - pbRemoveOperation.setCreatedAt( - toTimeTicket(removeOperation.getCreatedAt()), + const pbRemoveOperation = new PbOperation_Remove(); + pbRemoveOperation.parentCreatedAt = toTimeTicket( + removeOperation.getParentCreatedAt(), ); - pbRemoveOperation.setExecutedAt( - toTimeTicket(removeOperation.getExecutedAt()), + pbRemoveOperation.createdAt = toTimeTicket(removeOperation.getCreatedAt()); + pbRemoveOperation.executedAt = toTimeTicket( + removeOperation.getExecutedAt(), ); - pbOperation.setRemove(pbRemoveOperation); + pbOperation.body.case = 'remove'; + pbOperation.body.value = pbRemoveOperation; } else if (operation instanceof EditOperation) { const editOperation = operation as EditOperation; - const pbEditOperation = new PbOperation.Edit(); - pbEditOperation.setParentCreatedAt( - toTimeTicket(editOperation.getParentCreatedAt()), + const pbEditOperation = new PbOperation_Edit(); + pbEditOperation.parentCreatedAt = toTimeTicket( + editOperation.getParentCreatedAt(), ); - pbEditOperation.setFrom(toTextNodePos(editOperation.getFromPos())); - pbEditOperation.setTo(toTextNodePos(editOperation.getToPos())); - const pbCreatedAtMapByActor = pbEditOperation.getCreatedAtMapByActorMap(); + pbEditOperation.from = toTextNodePos(editOperation.getFromPos()); + pbEditOperation.to = toTextNodePos(editOperation.getToPos()); + const pbCreatedAtMapByActor = pbEditOperation.createdAtMapByActor; for (const [key, value] of editOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor.set(key, toTimeTicket(value)!); + pbCreatedAtMapByActor[key] = toTimeTicket(value)!; } - pbEditOperation.setContent(editOperation.getContent()); - const pbAttributes = pbEditOperation.getAttributesMap(); + pbEditOperation.content = editOperation.getContent(); + const pbAttributes = pbEditOperation.attributes; for (const [key, value] of editOperation.getAttributes()) { - pbAttributes.set(key, value); + pbAttributes[key] = value; } - pbEditOperation.setExecutedAt(toTimeTicket(editOperation.getExecutedAt())); - pbOperation.setEdit(pbEditOperation); + pbEditOperation.executedAt = toTimeTicket(editOperation.getExecutedAt()); + pbOperation.body.case = 'edit'; + pbOperation.body.value = pbEditOperation; } else if (operation instanceof StyleOperation) { const styleOperation = operation as StyleOperation; - const pbStyleOperation = new PbOperation.Style(); - pbStyleOperation.setParentCreatedAt( - toTimeTicket(styleOperation.getParentCreatedAt()), + const pbStyleOperation = new PbOperation_Style(); + pbStyleOperation.parentCreatedAt = toTimeTicket( + styleOperation.getParentCreatedAt(), ); - pbStyleOperation.setFrom(toTextNodePos(styleOperation.getFromPos())); - pbStyleOperation.setTo(toTextNodePos(styleOperation.getToPos())); - const pbCreatedAtMapByActor = pbStyleOperation.getCreatedAtMapByActorMap(); + pbStyleOperation.from = toTextNodePos(styleOperation.getFromPos()); + pbStyleOperation.to = toTextNodePos(styleOperation.getToPos()); + const pbCreatedAtMapByActor = pbStyleOperation.createdAtMapByActor; for (const [key, value] of styleOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor.set(key, toTimeTicket(value)!); + pbCreatedAtMapByActor[key] = toTimeTicket(value)!; } - const pbAttributes = pbStyleOperation.getAttributesMap(); + const pbAttributes = pbStyleOperation.attributes; for (const [key, value] of styleOperation.getAttributes()) { - pbAttributes.set(key, value); + pbAttributes[key] = value; } - pbStyleOperation.setExecutedAt( - toTimeTicket(styleOperation.getExecutedAt()), - ); - pbOperation.setStyle(pbStyleOperation); + pbStyleOperation.executedAt = toTimeTicket(styleOperation.getExecutedAt()); + pbOperation.body.case = 'style'; + pbOperation.body.value = pbStyleOperation; } else if (operation instanceof IncreaseOperation) { const increaseOperation = operation as IncreaseOperation; - const pbIncreaseOperation = new PbOperation.Increase(); - pbIncreaseOperation.setParentCreatedAt( - toTimeTicket(increaseOperation.getParentCreatedAt()), + const pbIncreaseOperation = new PbOperation_Increase(); + pbIncreaseOperation.parentCreatedAt = toTimeTicket( + increaseOperation.getParentCreatedAt(), ); - pbIncreaseOperation.setValue(toElementSimple(increaseOperation.getValue())); - pbIncreaseOperation.setExecutedAt( - toTimeTicket(increaseOperation.getExecutedAt()), + pbIncreaseOperation.value = toElementSimple(increaseOperation.getValue()); + pbIncreaseOperation.executedAt = toTimeTicket( + increaseOperation.getExecutedAt(), ); - pbOperation.setIncrease(pbIncreaseOperation); + pbOperation.body.case = 'increase'; + pbOperation.body.value = pbIncreaseOperation; } else if (operation instanceof TreeEditOperation) { const treeEditOperation = operation as TreeEditOperation; - const pbTreeEditOperation = new PbOperation.TreeEdit(); - const pbCreatedAtMapByActor = - pbTreeEditOperation.getCreatedAtMapByActorMap(); + const pbTreeEditOperation = new PbOperation_TreeEdit(); + const pbCreatedAtMapByActor = pbTreeEditOperation.createdAtMapByActor; for (const [key, value] of treeEditOperation.getMaxCreatedAtMapByActor()) { - pbCreatedAtMapByActor.set(key, toTimeTicket(value)!); + pbCreatedAtMapByActor[key] = toTimeTicket(value)!; } - pbTreeEditOperation.setParentCreatedAt( - toTimeTicket(treeEditOperation.getParentCreatedAt()), + pbTreeEditOperation.parentCreatedAt = toTimeTicket( + treeEditOperation.getParentCreatedAt(), ); - pbTreeEditOperation.setFrom(toTreePos(treeEditOperation.getFromPos())); - pbTreeEditOperation.setTo(toTreePos(treeEditOperation.getToPos())); - pbTreeEditOperation.setContentsList( - toTreeNodesWhenEdit(treeEditOperation.getContents()!), + pbTreeEditOperation.from = toTreePos(treeEditOperation.getFromPos()); + pbTreeEditOperation.to = toTreePos(treeEditOperation.getToPos()); + pbTreeEditOperation.contents = toTreeNodesWhenEdit( + treeEditOperation.getContents()!, ); - pbTreeEditOperation.setSplitLevel(treeEditOperation.getSplitLevel()); + pbTreeEditOperation.splitLevel = treeEditOperation.getSplitLevel(); - pbTreeEditOperation.setExecutedAt( - toTimeTicket(treeEditOperation.getExecutedAt()), + pbTreeEditOperation.executedAt = toTimeTicket( + treeEditOperation.getExecutedAt(), ); - pbOperation.setTreeEdit(pbTreeEditOperation); + pbOperation.body.case = 'treeEdit'; + pbOperation.body.value = pbTreeEditOperation; } else if (operation instanceof TreeStyleOperation) { const treeStyleOperation = operation as TreeStyleOperation; - const pbTreeStyleOperation = new PbOperation.TreeStyle(); - pbTreeStyleOperation.setParentCreatedAt( - toTimeTicket(treeStyleOperation.getParentCreatedAt()), + const pbTreeStyleOperation = new PbOperation_TreeStyle(); + pbTreeStyleOperation.parentCreatedAt = toTimeTicket( + treeStyleOperation.getParentCreatedAt(), ); - pbTreeStyleOperation.setFrom(toTreePos(treeStyleOperation.getFromPos())); - pbTreeStyleOperation.setTo(toTreePos(treeStyleOperation.getToPos())); + pbTreeStyleOperation.from = toTreePos(treeStyleOperation.getFromPos()); + pbTreeStyleOperation.to = toTreePos(treeStyleOperation.getToPos()); - const attributesMap = pbTreeStyleOperation.getAttributesMap(); + const attributesMap = pbTreeStyleOperation.attributes; for (const [key, value] of treeStyleOperation.getAttributes()) { - attributesMap.set(key, value); + attributesMap[key] = value; } - pbTreeStyleOperation.setExecutedAt( - toTimeTicket(treeStyleOperation.getExecutedAt()), + pbTreeStyleOperation.executedAt = toTimeTicket( + treeStyleOperation.getExecutedAt(), ); - pbOperation.setTreeStyle(pbTreeStyleOperation); + pbOperation.body.case = 'treeStyle'; + pbOperation.body.value = pbTreeStyleOperation; } else { throw new YorkieError(Code.Unimplemented, 'unimplemented operation'); } @@ -444,14 +477,15 @@ function toOperations(operations: Array): Array { * `toChange` converts the given model to Protobuf format. */ function toChange(change: Change): PbChange { - const pbChange = new PbChange(); - pbChange.setId(toChangeID(change.getID())); - pbChange.setMessage(change.getMessage()!); + const pbChange = new PbChange({ + id: toChangeID(change.getID()!), + message: change.getMessage(), + }); if (change.hasOperations()) { - pbChange.setOperationsList(toOperations(change.getOperations())); + pbChange.operations = toOperations(change.getOperations()); } if (change.hasPresenceChange()) { - pbChange.setPresenceChange(toPresenceChange(change.getPresenceChange()!)); + pbChange.presenceChange = toPresenceChange(change.getPresenceChange()!); } return pbChange; } @@ -473,11 +507,12 @@ function toChanges(changes: Array>): Array { function toRHTNodes(rht: ElementRHT): Array { const pbRHTNodes = []; for (const rhtNode of rht) { - const pbRHTNode = new PbRHTNode(); - pbRHTNode.setKey(rhtNode.getStrKey()); - // eslint-disable-next-line - pbRHTNode.setElement(toElement(rhtNode.getValue())); - pbRHTNodes.push(pbRHTNode); + pbRHTNodes.push( + new PbRHTNode({ + key: rhtNode.getStrKey(), + element: toElement(rhtNode.getValue()), + }), + ); } return pbRHTNodes; @@ -489,10 +524,11 @@ function toRHTNodes(rht: ElementRHT): Array { function toRGANodes(rgaTreeList: RGATreeList): Array { const pbRGANodes = []; for (const rgaTreeListNode of rgaTreeList) { - const pbRGANode = new PbRGANode(); - // eslint-disable-next-line - pbRGANode.setElement(toElement(rgaTreeListNode.getValue())); - pbRGANodes.push(pbRGANode); + pbRGANodes.push( + new PbRGANode({ + element: toElement(rgaTreeListNode.getValue()), + }), + ); } return pbRGANodes; @@ -508,17 +544,17 @@ function toTextNodes( for (const textNode of rgaTreeSplit) { const pbTextNode = new PbTextNode(); - pbTextNode.setId(toTextNodeID(textNode.getID())); - pbTextNode.setValue(textNode.getValue().getContent()); - pbTextNode.setRemovedAt(toTimeTicket(textNode.getRemovedAt())); + pbTextNode.id = toTextNodeID(textNode.getID()); + pbTextNode.value = textNode.getValue().getContent(); + pbTextNode.removedAt = toTimeTicket(textNode.getRemovedAt()); - const pbNodeAttrsMap = pbTextNode.getAttributesMap(); + const pbNodeAttrsMap = pbTextNode.attributes; const attrs = textNode.getValue().getAttrs(); for (const attr of attrs) { const pbNodeAttr = new PbNodeAttr(); - pbNodeAttr.setValue(attr.getValue()); - pbNodeAttr.setUpdatedAt(toTimeTicket(attr.getUpdatedAt())); - pbNodeAttrsMap.set(attr.getKey(), pbNodeAttr); + pbNodeAttr.value = attr.getValue(); + pbNodeAttr.updatedAt = toTimeTicket(attr.getUpdatedAt()); + pbNodeAttrsMap[attr.getKey()] = pbNodeAttr; } pbTextNodes.push(pbTextNode); @@ -532,16 +568,17 @@ function toTextNodes( */ function toTreeNodesWhenEdit(nodes: Array): Array { const pbTreeNodesList: Array = []; - if (!nodes || !nodes.length) { return pbTreeNodesList; } - nodes.forEach((node) => { - const pbTreeNodes = new PbTreeNodes(); - pbTreeNodes.setContentList(toTreeNodes(node)); - pbTreeNodesList.push(pbTreeNodes); - }); + for (const node of nodes) { + pbTreeNodesList.push( + new PbTreeNodes({ + content: toTreeNodes(node), + }), + ); + } return pbTreeNodesList; } @@ -556,29 +593,29 @@ function toTreeNodes(node: CRDTTreeNode): Array { const pbTreeNodes: Array = []; traverse(node, (n, depth) => { - const pbTreeNode = new PbTreeNode(); - pbTreeNode.setId(toTreeNodeID(n.id)); - pbTreeNode.setType(n.type); + const pbTreeNode = new PbTreeNode({ + id: toTreeNodeID(n.id), + type: n.type, + removedAt: toTimeTicket(n.removedAt), + depth, + }); + if (n.isText) { - pbTreeNode.setValue(n.value); + pbTreeNode.value = n.value; } if (n.insPrevID) { - pbTreeNode.setInsPrevId(toTreeNodeID(n.insPrevID)); + pbTreeNode.insPrevId = toTreeNodeID(n.insPrevID); } if (n.insNextID) { - pbTreeNode.setInsNextId(toTreeNodeID(n.insNextID)); + pbTreeNode.insNextId = toTreeNodeID(n.insNextID); } - pbTreeNode.setRemovedAt(toTimeTicket(n.removedAt)); - pbTreeNode.setDepth(depth); - if (n.attrs) { - const pbNodeAttrsMap = pbTreeNode.getAttributesMap(); for (const attr of n.attrs) { - const pbNodeAttr = new PbNodeAttr(); - pbNodeAttr.setValue(attr.getValue()); - pbNodeAttr.setUpdatedAt(toTimeTicket(attr.getUpdatedAt())); - pbNodeAttrsMap.set(attr.getKey(), pbNodeAttr); + pbTreeNode.attributes[attr.getKey()] = new PbNodeAttr({ + value: attr.getValue(), + updatedAt: toTimeTicket(attr.getUpdatedAt()), + }); } } @@ -592,14 +629,14 @@ function toTreeNodes(node: CRDTTreeNode): Array { * `toObject` converts the given model to Protobuf format. */ function toObject(obj: CRDTObject): PbJSONElement { - const pbObject = new PbJSONElement.JSONObject(); - pbObject.setNodesList(toRHTNodes(obj.getRHT())); - pbObject.setCreatedAt(toTimeTicket(obj.getCreatedAt())); - pbObject.setMovedAt(toTimeTicket(obj.getMovedAt())); - pbObject.setRemovedAt(toTimeTicket(obj.getRemovedAt())); - const pbElement = new PbJSONElement(); - pbElement.setJsonObject(pbObject); + pbElement.body.case = 'jsonObject'; + pbElement.body.value = new PbJSONElement_JSONObject({ + nodes: toRHTNodes(obj.getRHT()), + createdAt: toTimeTicket(obj.getCreatedAt()), + movedAt: toTimeTicket(obj.getMovedAt()), + removedAt: toTimeTicket(obj.getRemovedAt()), + }); return pbElement; } @@ -607,14 +644,14 @@ function toObject(obj: CRDTObject): PbJSONElement { * `toArray` converts the given model to Protobuf format. */ function toArray(arr: CRDTArray): PbJSONElement { - const pbArray = new PbJSONElement.JSONArray(); - pbArray.setNodesList(toRGANodes(arr.getElements())); - pbArray.setCreatedAt(toTimeTicket(arr.getCreatedAt())); - pbArray.setMovedAt(toTimeTicket(arr.getMovedAt())); - pbArray.setRemovedAt(toTimeTicket(arr.getRemovedAt())); - const pbElement = new PbJSONElement(); - pbElement.setJsonArray(pbArray); + pbElement.body.case = 'jsonArray'; + pbElement.body.value = new PbJSONElement_JSONArray({ + nodes: toRGANodes(arr.getElements()), + createdAt: toTimeTicket(arr.getCreatedAt()), + movedAt: toTimeTicket(arr.getMovedAt()), + removedAt: toTimeTicket(arr.getRemovedAt()), + }); return pbElement; } @@ -622,15 +659,15 @@ function toArray(arr: CRDTArray): PbJSONElement { * `toPrimitive` converts the given model to Protobuf format. */ function toPrimitive(primitive: Primitive): PbJSONElement { - const pbPrimitive = new PbJSONElement.Primitive(); - pbPrimitive.setType(toValueType(primitive.getType())); - pbPrimitive.setValue(primitive.toBytes()); - pbPrimitive.setCreatedAt(toTimeTicket(primitive.getCreatedAt())); - pbPrimitive.setMovedAt(toTimeTicket(primitive.getMovedAt())); - pbPrimitive.setRemovedAt(toTimeTicket(primitive.getRemovedAt())); - const pbElement = new PbJSONElement(); - pbElement.setPrimitive(pbPrimitive); + pbElement.body.case = 'primitive'; + pbElement.body.value = new PbJSONElement_Primitive({ + type: toValueType(primitive.getType()), + value: primitive.toBytes(), + createdAt: toTimeTicket(primitive.getCreatedAt()), + movedAt: toTimeTicket(primitive.getMovedAt()), + removedAt: toTimeTicket(primitive.getRemovedAt()), + }); return pbElement; } @@ -638,14 +675,14 @@ function toPrimitive(primitive: Primitive): PbJSONElement { * `toText` converts the given model to Protobuf format. */ function toText(text: CRDTText>): PbJSONElement { - const pbText = new PbJSONElement.Text(); - pbText.setNodesList(toTextNodes(text.getRGATreeSplit())); - pbText.setCreatedAt(toTimeTicket(text.getCreatedAt())); - pbText.setMovedAt(toTimeTicket(text.getMovedAt())); - pbText.setRemovedAt(toTimeTicket(text.getRemovedAt())); - const pbElement = new PbJSONElement(); - pbElement.setText(pbText); + pbElement.body.case = 'text'; + pbElement.body.value = new PbJSONElement_Text({ + nodes: toTextNodes(text.getRGATreeSplit()), + createdAt: toTimeTicket(text.getCreatedAt()), + movedAt: toTimeTicket(text.getMovedAt()), + removedAt: toTimeTicket(text.getRemovedAt()), + }); return pbElement; } @@ -653,15 +690,15 @@ function toText(text: CRDTText>): PbJSONElement { * `toCounter` converts the given model to Protobuf format. */ function toCounter(counter: CRDTCounter): PbJSONElement { - const pbCounter = new PbJSONElement.Counter(); - pbCounter.setType(toCounterType(counter.getType())); - pbCounter.setValue(counter.toBytes()); - pbCounter.setCreatedAt(toTimeTicket(counter.getCreatedAt())); - pbCounter.setMovedAt(toTimeTicket(counter.getMovedAt())); - pbCounter.setRemovedAt(toTimeTicket(counter.getRemovedAt())); - const pbElement = new PbJSONElement(); - pbElement.setCounter(pbCounter); + pbElement.body.case = 'counter'; + pbElement.body.value = new PbJSONElement_Counter({ + type: toCounterType(counter.getType()), + value: counter.toBytes(), + createdAt: toTimeTicket(counter.getCreatedAt()), + movedAt: toTimeTicket(counter.getMovedAt()), + removedAt: toTimeTicket(counter.getRemovedAt()), + }); return pbElement; } @@ -669,14 +706,14 @@ function toCounter(counter: CRDTCounter): PbJSONElement { * `toTree` converts the given model to Protobuf format. */ function toTree(tree: CRDTTree): PbJSONElement { - const pbTree = new PbJSONElement.Tree(); - pbTree.setNodesList(toTreeNodes(tree.getRoot())); - pbTree.setCreatedAt(toTimeTicket(tree.getCreatedAt())); - pbTree.setMovedAt(toTimeTicket(tree.getMovedAt())); - pbTree.setRemovedAt(toTimeTicket(tree.getRemovedAt())); - const pbElement = new PbJSONElement(); - pbElement.setTree(pbTree); + pbElement.body.case = 'tree'; + pbElement.body.value = new PbJSONElement_Tree({ + nodes: toTreeNodes(tree.getRoot()), + createdAt: toTimeTicket(tree.getCreatedAt()), + movedAt: toTimeTicket(tree.getMovedAt()), + removedAt: toTimeTicket(tree.getRemovedAt()), + }); return pbElement; } @@ -686,33 +723,38 @@ function toTree(tree: CRDTTree): PbJSONElement { function toElement(element: CRDTElement): PbJSONElement { if (element instanceof CRDTObject) { return toObject(element); - } else if (element instanceof CRDTArray) { + } + if (element instanceof CRDTArray) { return toArray(element); - } else if (element instanceof Primitive) { + } + if (element instanceof Primitive) { return toPrimitive(element); - } else if (element instanceof CRDTText) { + } + if (element instanceof CRDTText) { return toText(element); - } else if (element instanceof CRDTCounter) { + } + if (element instanceof CRDTCounter) { return toCounter(element); - } else if (element instanceof CRDTTree) { + } + if (element instanceof CRDTTree) { return toTree(element); - } else { - throw new YorkieError(Code.Unimplemented, `unimplemented element`); } + + throw new YorkieError(Code.Unimplemented, `unimplemented element`); } /** * `toChangePack` converts the given model to Protobuf format. */ function toChangePack(pack: ChangePack): PbChangePack { - const pbChangePack = new PbChangePack(); - pbChangePack.setDocumentKey(pack.getDocumentKey()); - pbChangePack.setCheckpoint(toCheckpoint(pack.getCheckpoint())); - pbChangePack.setIsRemoved(pack.getIsRemoved()); - pbChangePack.setChangesList(toChanges(pack.getChanges())); - pbChangePack.setSnapshot(pack.getSnapshot()!); - pbChangePack.setMinSyncedTicket(toTimeTicket(pack.getMinSyncedTicket())); - return pbChangePack; + return new PbChangePack({ + documentKey: pack.getDocumentKey(), + checkpoint: toCheckpoint(pack.getCheckpoint()), + isRemoved: pack.getIsRemoved(), + changes: toChanges(pack.getChanges()), + snapshot: pack.getSnapshot(), + minSyncedTicket: toTimeTicket(pack.getMinSyncedTicket()), + }); } /** @@ -720,9 +762,9 @@ function toChangePack(pack: ChangePack): PbChangePack { */ function fromChangeID(pbChangeID: PbChangeID): ChangeID { return ChangeID.of( - pbChangeID.getClientSeq(), - Long.fromString(pbChangeID.getLamport(), true), - toHexString(pbChangeID.getActorId_asU8()), + pbChangeID.clientSeq, + Long.fromString(pbChangeID.lamport, true), + toHexString(pbChangeID.actorId), ); } @@ -735,9 +777,9 @@ function fromTimeTicket(pbTimeTicket?: PbTimeTicket): TimeTicket | undefined { } return TimeTicket.of( - Long.fromString(pbTimeTicket.getLamport(), true), - pbTimeTicket.getDelimiter(), - toHexString(pbTimeTicket.getActorId_asU8()), + Long.fromString(pbTimeTicket.lamport, true), + pbTimeTicket.delimiter, + toHexString(pbTimeTicket.actorId), ); } @@ -746,7 +788,7 @@ function fromTimeTicket(pbTimeTicket?: PbTimeTicket): TimeTicket | undefined { */ function fromPresence

(pbPresence: PbPresence): P { const data: Record = {}; - pbPresence.getDataMap().forEach((value: string, key: string) => { + Object.entries(pbPresence.data).forEach(([key, value]) => { data[key] = JSON.parse(value); }); @@ -759,31 +801,31 @@ function fromPresence

(pbPresence: PbPresence): P { function fromPresenceChange

( pbPresenceChange: PbPresenceChange, ): PresenceChange

{ - const type = pbPresenceChange.getType(); - - if (type === PbPresenceChange.ChangeType.CHANGE_TYPE_PUT) { - const presence = fromPresence

(pbPresenceChange.getPresence()!); + const type = pbPresenceChange.type; + if (type === PbPresenceChange_ChangeType.PUT) { + const presence = fromPresence

(pbPresenceChange.presence!); return { type: PresenceChangeType.Put, presence, }; - } else if (type === PbPresenceChange.ChangeType.CHANGE_TYPE_CLEAR) { + } + if (type === PbPresenceChange_ChangeType.CLEAR) { return { type: PresenceChangeType.Clear, }; - } else { - throw new YorkieError(Code.Unsupported, `unsupported type: ${type}`); } + + throw new YorkieError(Code.Unsupported, `unsupported type: ${type}`); } /** * `fromPresences` converts the given Protobuf format to model format. */ -function fromPresences

( - pbPresences: jspb.Map, -): Map { +function fromPresences

(pbPresences: { + [key: string]: PbPresence; +}): Map { const presences = new Map(); - pbPresences.forEach((pbPresence: PbPresence, actorID: string) => { + Object.entries(pbPresences).forEach(([actorID, pbPresence]) => { presences.set(actorID, fromPresence(pbPresence)); }); return presences; @@ -794,21 +836,21 @@ function fromPresences

( */ function fromValueType(pbValueType: PbValueType): PrimitiveType { switch (pbValueType) { - case PbValueType.VALUE_TYPE_NULL: + case PbValueType.NULL: return PrimitiveType.Null; - case PbValueType.VALUE_TYPE_BOOLEAN: + case PbValueType.BOOLEAN: return PrimitiveType.Boolean; - case PbValueType.VALUE_TYPE_INTEGER: + case PbValueType.INTEGER: return PrimitiveType.Integer; - case PbValueType.VALUE_TYPE_LONG: + case PbValueType.LONG: return PrimitiveType.Long; - case PbValueType.VALUE_TYPE_DOUBLE: + case PbValueType.DOUBLE: return PrimitiveType.Double; - case PbValueType.VALUE_TYPE_STRING: + case PbValueType.STRING: return PrimitiveType.String; - case PbValueType.VALUE_TYPE_BYTES: + case PbValueType.BYTES: return PrimitiveType.Bytes; - case PbValueType.VALUE_TYPE_DATE: + case PbValueType.DATE: return PrimitiveType.Date; } throw new YorkieError( @@ -822,9 +864,9 @@ function fromValueType(pbValueType: PbValueType): PrimitiveType { */ function fromCounterType(pbValueType: PbValueType): CounterType { switch (pbValueType) { - case PbValueType.VALUE_TYPE_INTEGER_CNT: + case PbValueType.INTEGER_CNT: return CounterType.IntegerCnt; - case PbValueType.VALUE_TYPE_LONG_CNT: + case PbValueType.LONG_CNT: return CounterType.LongCnt; } throw new YorkieError( @@ -837,52 +879,48 @@ function fromCounterType(pbValueType: PbValueType): CounterType { * `fromElementSimple` converts the given Protobuf format to model format. */ function fromElementSimple(pbElementSimple: PbJSONElementSimple): CRDTElement { - switch (pbElementSimple.getType()) { - case PbValueType.VALUE_TYPE_JSON_OBJECT: - if (!pbElementSimple.getValue()) { - return CRDTObject.create( - fromTimeTicket(pbElementSimple.getCreatedAt())!, - ); + switch (pbElementSimple.type) { + case PbValueType.JSON_OBJECT: + if (!pbElementSimple.value) { + return CRDTObject.create(fromTimeTicket(pbElementSimple.createdAt)!); } - return bytesToObject(pbElementSimple.getValue_asU8()); - case PbValueType.VALUE_TYPE_JSON_ARRAY: - if (!pbElementSimple.getValue()) { - return CRDTArray.create( - fromTimeTicket(pbElementSimple.getCreatedAt())!, - ); + return bytesToObject(pbElementSimple.value); + case PbValueType.JSON_ARRAY: + if (!pbElementSimple.value) { + return CRDTArray.create(fromTimeTicket(pbElementSimple.createdAt)!); } - return bytesToArray(pbElementSimple.getValue_asU8()); - case PbValueType.VALUE_TYPE_TEXT: + return bytesToArray(pbElementSimple.value); + case PbValueType.TEXT: return CRDTText.create( RGATreeSplit.create(), - fromTimeTicket(pbElementSimple.getCreatedAt())!, + fromTimeTicket(pbElementSimple.createdAt)!, ); - case PbValueType.VALUE_TYPE_TREE: - return bytesToTree(pbElementSimple.getValue_asU8())!; - case PbValueType.VALUE_TYPE_NULL: - case PbValueType.VALUE_TYPE_BOOLEAN: - case PbValueType.VALUE_TYPE_INTEGER: - case PbValueType.VALUE_TYPE_LONG: - case PbValueType.VALUE_TYPE_DOUBLE: - case PbValueType.VALUE_TYPE_STRING: - case PbValueType.VALUE_TYPE_BYTES: - case PbValueType.VALUE_TYPE_DATE: + case PbValueType.TREE: + return bytesToTree(pbElementSimple.value)!; + case PbValueType.NULL: + case PbValueType.BOOLEAN: + case PbValueType.INTEGER: + case PbValueType.LONG: + case PbValueType.DOUBLE: + case PbValueType.STRING: + case PbValueType.BYTES: + case PbValueType.DATE: return Primitive.of( Primitive.valueFromBytes( - fromValueType(pbElementSimple.getType()), - pbElementSimple.getValue_asU8(), + fromValueType(pbElementSimple.type), + pbElementSimple.value, ), - fromTimeTicket(pbElementSimple.getCreatedAt())!, + fromTimeTicket(pbElementSimple.createdAt)!, ); - case PbValueType.VALUE_TYPE_INTEGER_CNT: - case PbValueType.VALUE_TYPE_LONG_CNT: + case PbValueType.INTEGER_CNT: + case PbValueType.LONG_CNT: return CRDTCounter.create( - fromCounterType(pbElementSimple.getType()), + fromCounterType(pbElementSimple.type), CRDTCounter.valueFromBytes( - fromCounterType(pbElementSimple.getType()), - pbElementSimple.getValue_asU8(), + fromCounterType(pbElementSimple.type), + pbElementSimple.value, ), - fromTimeTicket(pbElementSimple.getCreatedAt())!, + fromTimeTicket(pbElementSimple.createdAt)!, ); } } @@ -893,10 +931,10 @@ function fromElementSimple(pbElementSimple: PbJSONElementSimple): CRDTElement { function fromTextNodePos(pbTextNodePos: PbTextNodePos): RGATreeSplitPos { return RGATreeSplitPos.of( RGATreeSplitNodeID.of( - fromTimeTicket(pbTextNodePos.getCreatedAt())!, - pbTextNodePos.getOffset(), + fromTimeTicket(pbTextNodePos.createdAt)!, + pbTextNodePos.offset, ), - pbTextNodePos.getRelativeOffset(), + pbTextNodePos.relativeOffset, ); } @@ -905,8 +943,8 @@ function fromTextNodePos(pbTextNodePos: PbTextNodePos): RGATreeSplitPos { */ function fromTextNodeID(pbTextNodeID: PbTextNodeID): RGATreeSplitNodeID { return RGATreeSplitNodeID.of( - fromTimeTicket(pbTextNodeID.getCreatedAt())!, - pbTextNodeID.getOffset(), + fromTimeTicket(pbTextNodeID.createdAt)!, + pbTextNodeID.offset, ); } @@ -914,20 +952,16 @@ function fromTextNodeID(pbTextNodeID: PbTextNodeID): RGATreeSplitNodeID { * `fromTextNode` converts the given Protobuf format to model format. */ function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode { - const textValue = CRDTTextValue.create(pbTextNode.getValue()); - pbTextNode.getAttributesMap().forEach((value, key) => { - textValue.setAttr( - key, - value.getValue(), - fromTimeTicket(value.getUpdatedAt())!, - ); + const textValue = CRDTTextValue.create(pbTextNode.value); + Object.entries(pbTextNode.attributes).forEach(([key, value]) => { + textValue.setAttr(key, value.value, fromTimeTicket(value.updatedAt)!); }); const textNode = RGATreeSplitNode.create( - fromTextNodeID(pbTextNode.getId()!), + fromTextNodeID(pbTextNode.id!), textValue, ); - textNode.remove(fromTimeTicket(pbTextNode.getRemovedAt())); + textNode.remove(fromTimeTicket(pbTextNode.removedAt)); return textNode; } @@ -936,8 +970,8 @@ function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode { */ function fromTreePos(pbTreePos: PbTreePos): CRDTTreePos { return CRDTTreePos.of( - fromTreeNodeID(pbTreePos.getParentId()!), - fromTreeNodeID(pbTreePos.getLeftSiblingId()!), + fromTreeNodeID(pbTreePos.parentId!), + fromTreeNodeID(pbTreePos.leftSiblingId!), ); } @@ -946,8 +980,8 @@ function fromTreePos(pbTreePos: PbTreePos): CRDTTreePos { */ function fromTreeNodeID(pbTreeNodeID: PbTreeNodeID): CRDTTreeNodeID { return CRDTTreeNodeID.of( - fromTimeTicket(pbTreeNodeID.getCreatedAt())!, - pbTreeNodeID.getOffset(), + fromTimeTicket(pbTreeNodeID.createdAt)!, + pbTreeNodeID.offset, ); } @@ -963,7 +997,7 @@ function fromTreeNodesWhenEdit( const treeNodes: Array = []; pbTreeNodes.forEach((node) => { - const treeNode = fromTreeNodes(node.getContentList()); + const treeNode = fromTreeNodes(node.content); treeNodes.push(treeNode!); }); @@ -989,7 +1023,7 @@ function fromTreeNodes( for (let i = nodes.length - 2; i >= 0; i--) { let parent: CRDTTreeNode; for (let j = i + 1; j < nodes.length; j++) { - if (pbTreeNodes[i].getDepth() - 1 === pbTreeNodes[j].getDepth()) { + if (pbTreeNodes[i].depth - 1 === pbTreeNodes[j].depth) { parent = nodes[j]; break; } @@ -1006,27 +1040,27 @@ function fromTreeNodes( * `fromTreeNode` converts the given Protobuf format to model format. */ function fromTreeNode(pbTreeNode: PbTreeNode): CRDTTreeNode { - const id = fromTreeNodeID(pbTreeNode.getId()!); - const node = CRDTTreeNode.create(id, pbTreeNode.getType()); + const id = fromTreeNodeID(pbTreeNode.id!); + const node = CRDTTreeNode.create(id, pbTreeNode.type); if (node.isText) { - node.value = pbTreeNode.getValue(); + node.value = pbTreeNode.value; } else { const attrs = RHT.create(); - pbTreeNode.getAttributesMap().forEach((value, key) => { - attrs.set(key, value.getValue(), fromTimeTicket(value.getUpdatedAt())!); + Object.entries(pbTreeNode.attributes).forEach(([key, value]) => { + attrs.set(key, value.value, fromTimeTicket(value.updatedAt)!); }); node.attrs = attrs; } - if (pbTreeNode.hasInsPrevId()) { - node.insPrevID = fromTreeNodeID(pbTreeNode.getInsPrevId()!); + if (pbTreeNode.insPrevId) { + node.insPrevID = fromTreeNodeID(pbTreeNode.insPrevId!); } - if (pbTreeNode.hasInsNextId()) { - node.insNextID = fromTreeNodeID(pbTreeNode.getInsNextId()!); + if (pbTreeNode.insPrevId) { + node.insNextID = fromTreeNodeID(pbTreeNode.insNextId!); } - node.removedAt = fromTimeTicket(pbTreeNode.getRemovedAt()); + node.removedAt = fromTimeTicket(pbTreeNode.removedAt); return node; } @@ -1039,112 +1073,120 @@ function fromOperations(pbOperations: Array): Array { for (const pbOperation of pbOperations) { let operation: Operation; - if (pbOperation.hasSet()) { - const pbSetOperation = pbOperation.getSet(); + if (pbOperation.body.case === 'set') { + const pbSetOperation = pbOperation.body.value; operation = SetOperation.create( - pbSetOperation!.getKey(), - fromElementSimple(pbSetOperation!.getValue()!), - fromTimeTicket(pbSetOperation!.getParentCreatedAt())!, - fromTimeTicket(pbSetOperation!.getExecutedAt())!, + pbSetOperation!.key, + fromElementSimple(pbSetOperation!.value!), + fromTimeTicket(pbSetOperation!.parentCreatedAt)!, + fromTimeTicket(pbSetOperation!.executedAt)!, ); - } else if (pbOperation.hasAdd()) { - const pbAddOperation = pbOperation.getAdd(); + } else if (pbOperation.body.case === 'add') { + const pbAddOperation = pbOperation.body.value; operation = AddOperation.create( - fromTimeTicket(pbAddOperation!.getParentCreatedAt())!, - fromTimeTicket(pbAddOperation!.getPrevCreatedAt())!, - fromElementSimple(pbAddOperation!.getValue()!), - fromTimeTicket(pbAddOperation!.getExecutedAt())!, + fromTimeTicket(pbAddOperation!.parentCreatedAt)!, + fromTimeTicket(pbAddOperation!.prevCreatedAt)!, + fromElementSimple(pbAddOperation!.value!), + fromTimeTicket(pbAddOperation!.executedAt)!, ); - } else if (pbOperation.hasMove()) { - const pbMoveOperation = pbOperation.getMove(); + } else if (pbOperation.body.case === 'move') { + const pbMoveOperation = pbOperation.body.value; operation = MoveOperation.create( - fromTimeTicket(pbMoveOperation!.getParentCreatedAt())!, - fromTimeTicket(pbMoveOperation!.getPrevCreatedAt())!, - fromTimeTicket(pbMoveOperation!.getCreatedAt())!, - fromTimeTicket(pbMoveOperation!.getExecutedAt())!, + fromTimeTicket(pbMoveOperation!.parentCreatedAt)!, + fromTimeTicket(pbMoveOperation!.prevCreatedAt)!, + fromTimeTicket(pbMoveOperation!.createdAt)!, + fromTimeTicket(pbMoveOperation!.executedAt)!, ); - } else if (pbOperation.hasRemove()) { - const pbRemoveOperation = pbOperation.getRemove(); + } else if (pbOperation.body.case === 'remove') { + const pbRemoveOperation = pbOperation.body.value; operation = RemoveOperation.create( - fromTimeTicket(pbRemoveOperation!.getParentCreatedAt())!, - fromTimeTicket(pbRemoveOperation!.getCreatedAt())!, - fromTimeTicket(pbRemoveOperation!.getExecutedAt())!, + fromTimeTicket(pbRemoveOperation!.parentCreatedAt)!, + fromTimeTicket(pbRemoveOperation!.createdAt)!, + fromTimeTicket(pbRemoveOperation!.executedAt)!, ); - } else if (pbOperation.hasEdit()) { - const pbEditOperation = pbOperation.getEdit(); + } else if (pbOperation.body.case === 'edit') { + const pbEditOperation = pbOperation.body.value; const createdAtMapByActor = new Map(); - pbEditOperation!.getCreatedAtMapByActorMap().forEach((value, key) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }); + Object.entries(pbEditOperation!.createdAtMapByActor).forEach( + ([key, value]) => { + createdAtMapByActor.set(key, fromTimeTicket(value)); + }, + ); const attributes = new Map(); - pbEditOperation!.getAttributesMap().forEach((value, key) => { + Object.entries(pbEditOperation!.attributes).forEach(([key, value]) => { attributes.set(key, value); }); operation = EditOperation.create( - fromTimeTicket(pbEditOperation!.getParentCreatedAt())!, - fromTextNodePos(pbEditOperation!.getFrom()!), - fromTextNodePos(pbEditOperation!.getTo()!), + fromTimeTicket(pbEditOperation!.parentCreatedAt)!, + fromTextNodePos(pbEditOperation!.from!), + fromTextNodePos(pbEditOperation!.to!), createdAtMapByActor, - pbEditOperation!.getContent(), + pbEditOperation!.content, attributes, - fromTimeTicket(pbEditOperation!.getExecutedAt())!, + fromTimeTicket(pbEditOperation!.executedAt)!, ); - } else if (pbOperation.hasStyle()) { - const pbStyleOperation = pbOperation.getStyle(); + } else if (pbOperation.body.case === 'style') { + const pbStyleOperation = pbOperation.body.value; const createdAtMapByActor = new Map(); - pbStyleOperation!.getCreatedAtMapByActorMap().forEach((value, key) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }); + Object.entries(pbStyleOperation!.createdAtMapByActor).forEach( + ([key, value]) => { + createdAtMapByActor.set(key, fromTimeTicket(value)); + }, + ); const attributes = new Map(); - pbStyleOperation!.getAttributesMap().forEach((value, key) => { + Object.entries(pbStyleOperation!.attributes).forEach(([key, value]) => { attributes.set(key, value); }); operation = StyleOperation.create( - fromTimeTicket(pbStyleOperation!.getParentCreatedAt())!, - fromTextNodePos(pbStyleOperation!.getFrom()!), - fromTextNodePos(pbStyleOperation!.getTo()!), + fromTimeTicket(pbStyleOperation!.parentCreatedAt)!, + fromTextNodePos(pbStyleOperation!.from!), + fromTextNodePos(pbStyleOperation!.to!), createdAtMapByActor, attributes, - fromTimeTicket(pbStyleOperation!.getExecutedAt())!, + fromTimeTicket(pbStyleOperation!.executedAt)!, ); - } else if (pbOperation.hasSelect()) { + } else if (pbOperation.body.case === 'select') { // TODO(hackerwins): Select is deprecated. continue; - } else if (pbOperation.hasIncrease()) { - const pbIncreaseOperation = pbOperation.getIncrease(); + } else if (pbOperation.body.case === 'increase') { + const pbIncreaseOperation = pbOperation.body.value; operation = IncreaseOperation.create( - fromTimeTicket(pbIncreaseOperation!.getParentCreatedAt())!, - fromElementSimple(pbIncreaseOperation!.getValue()!), - fromTimeTicket(pbIncreaseOperation!.getExecutedAt())!, + fromTimeTicket(pbIncreaseOperation!.parentCreatedAt)!, + fromElementSimple(pbIncreaseOperation!.value!), + fromTimeTicket(pbIncreaseOperation!.executedAt)!, ); - } else if (pbOperation.hasTreeEdit()) { - const pbTreeEditOperation = pbOperation.getTreeEdit(); + } else if (pbOperation.body.case === 'treeEdit') { + const pbTreeEditOperation = pbOperation.body.value; const createdAtMapByActor = new Map(); - pbTreeEditOperation!.getCreatedAtMapByActorMap().forEach((value, key) => { - createdAtMapByActor.set(key, fromTimeTicket(value)); - }); + Object.entries(pbTreeEditOperation!.createdAtMapByActor).forEach( + ([key, value]) => { + createdAtMapByActor.set(key, fromTimeTicket(value)); + }, + ); operation = TreeEditOperation.create( - fromTimeTicket(pbTreeEditOperation!.getParentCreatedAt())!, - fromTreePos(pbTreeEditOperation!.getFrom()!), - fromTreePos(pbTreeEditOperation!.getTo()!), - fromTreeNodesWhenEdit(pbTreeEditOperation!.getContentsList()), - pbTreeEditOperation!.getSplitLevel(), + fromTimeTicket(pbTreeEditOperation!.parentCreatedAt)!, + fromTreePos(pbTreeEditOperation!.from!), + fromTreePos(pbTreeEditOperation!.to!), + fromTreeNodesWhenEdit(pbTreeEditOperation!.contents), + pbTreeEditOperation!.splitLevel, createdAtMapByActor, - fromTimeTicket(pbTreeEditOperation!.getExecutedAt())!, + fromTimeTicket(pbTreeEditOperation!.executedAt)!, ); - } else if (pbOperation.hasTreeStyle()) { - const pbTreeStyleOperation = pbOperation.getTreeStyle(); + } else if (pbOperation.body.case === 'treeStyle') { + const pbTreeStyleOperation = pbOperation.body.value; const attributes = new Map(); - pbTreeStyleOperation!.getAttributesMap().forEach((value, key) => { - attributes.set(key, value); - }); + Object.entries(pbTreeStyleOperation!.attributes).forEach( + ([key, value]) => { + attributes.set(key, value); + }, + ); operation = TreeStyleOperation.create( - fromTimeTicket(pbTreeStyleOperation!.getParentCreatedAt())!, - fromTreePos(pbTreeStyleOperation!.getFrom()!), - fromTreePos(pbTreeStyleOperation!.getTo()!), + fromTimeTicket(pbTreeStyleOperation!.parentCreatedAt)!, + fromTreePos(pbTreeStyleOperation!.from!), + fromTreePos(pbTreeStyleOperation!.to!), attributes, - fromTimeTicket(pbTreeStyleOperation!.getExecutedAt())!, + fromTimeTicket(pbTreeStyleOperation!.executedAt)!, ); } else { throw new YorkieError(Code.Unimplemented, `unimplemented operation`); @@ -1167,12 +1209,12 @@ function fromChanges

( for (const pbChange of pbChanges) { changes.push( Change.create({ - id: fromChangeID(pbChange.getId()!), - operations: fromOperations(pbChange.getOperationsList()), - presenceChange: pbChange.hasPresenceChange() - ? fromPresenceChange(pbChange.getPresenceChange()!) + id: fromChangeID(pbChange.id!), + operations: fromOperations(pbChange.operations), + presenceChange: pbChange.presenceChange + ? fromPresenceChange(pbChange.presenceChange!) : undefined, - message: pbChange.getMessage(), + message: pbChange.message, }), ); } @@ -1185,8 +1227,8 @@ function fromChanges

( */ function fromCheckpoint(pbCheckpoint: PbCheckpoint): Checkpoint { return Checkpoint.of( - Long.fromString(pbCheckpoint.getServerSeq(), true), - pbCheckpoint.getClientSeq(), + Long.fromString(pbCheckpoint.serverSeq, true), + pbCheckpoint.clientSeq, ); } @@ -1197,63 +1239,60 @@ function fromChangePack

( pbPack: PbChangePack, ): ChangePack

{ return ChangePack.create

( - pbPack.getDocumentKey()!, - fromCheckpoint(pbPack.getCheckpoint()!), - pbPack.getIsRemoved(), - fromChanges(pbPack.getChangesList()), - pbPack.getSnapshot_asU8(), - fromTimeTicket(pbPack.getMinSyncedTicket()), + pbPack.documentKey!, + fromCheckpoint(pbPack.checkpoint!), + pbPack.isRemoved, + fromChanges(pbPack.changes), + pbPack.snapshot, + fromTimeTicket(pbPack.minSyncedTicket), ); } /** * `fromObject` converts the given Protobuf format to model format. */ -function fromObject(pbObject: PbJSONElement.JSONObject): CRDTObject { +function fromObject(pbObject: PbJSONElement_JSONObject): CRDTObject { const rht = new ElementRHT(); - for (const pbRHTNode of pbObject.getNodesList()) { - const value = fromElement(pbRHTNode.getElement()!); - rht.set(pbRHTNode.getKey(), value, value.getPositionedAt()); + for (const pbRHTNode of pbObject.nodes) { + const value = fromElement(pbRHTNode.element!); + rht.set(pbRHTNode.key, value, value.getPositionedAt()); } - const obj = new CRDTObject(fromTimeTicket(pbObject.getCreatedAt())!, rht); - obj.setMovedAt(fromTimeTicket(pbObject.getMovedAt())); - obj.setRemovedAt(fromTimeTicket(pbObject.getRemovedAt())); + const obj = new CRDTObject(fromTimeTicket(pbObject.createdAt)!, rht); + obj.setMovedAt(fromTimeTicket(pbObject.movedAt)); + obj.setRemovedAt(fromTimeTicket(pbObject.removedAt)); return obj; } /** * `fromArray` converts the given Protobuf format to model format. */ -function fromArray(pbArray: PbJSONElement.JSONArray): CRDTArray { +function fromArray(pbArray: PbJSONElement_JSONArray): CRDTArray { const rgaTreeList = new RGATreeList(); - for (const pbRGANode of pbArray.getNodesList()) { + for (const pbRGANode of pbArray.nodes) { // eslint-disable-next-line - rgaTreeList.insert(fromElement(pbRGANode.getElement()!)); + rgaTreeList.insert(fromElement(pbRGANode.element!)); } - const arr = new CRDTArray( - fromTimeTicket(pbArray.getCreatedAt())!, - rgaTreeList, - ); - arr.setMovedAt(fromTimeTicket(pbArray.getMovedAt())); - arr.setRemovedAt(fromTimeTicket(pbArray.getRemovedAt())); + const arr = new CRDTArray(fromTimeTicket(pbArray.createdAt)!, rgaTreeList); + arr.setMovedAt(fromTimeTicket(pbArray.movedAt)); + arr.setRemovedAt(fromTimeTicket(pbArray.removedAt)); return arr; } /** * `fromPrimitive` converts the given Protobuf format to model format. */ -function fromPrimitive(pbPrimitive: PbJSONElement.Primitive): Primitive { +function fromPrimitive(pbPrimitive: PbJSONElement_Primitive): Primitive { const primitive = Primitive.of( Primitive.valueFromBytes( - fromValueType(pbPrimitive.getType()), - pbPrimitive.getValue_asU8(), + fromValueType(pbPrimitive.type), + pbPrimitive.value, ), - fromTimeTicket(pbPrimitive.getCreatedAt())!, + fromTimeTicket(pbPrimitive.createdAt)!, ); - primitive.setMovedAt(fromTimeTicket(pbPrimitive.getMovedAt())); - primitive.setRemovedAt(fromTimeTicket(pbPrimitive.getRemovedAt())); + primitive.setMovedAt(fromTimeTicket(pbPrimitive.movedAt)); + primitive.setRemovedAt(fromTimeTicket(pbPrimitive.removedAt)); return primitive; } @@ -1261,70 +1300,67 @@ function fromPrimitive(pbPrimitive: PbJSONElement.Primitive): Primitive { * `fromText` converts the given Protobuf format to model format. */ function fromText( - pbText: PbJSONElement.Text, + pbText: PbJSONElement_Text, ): CRDTText { const rgaTreeSplit = new RGATreeSplit(); let prev = rgaTreeSplit.getHead(); - for (const pbNode of pbText.getNodesList()) { + for (const pbNode of pbText.nodes) { const current = rgaTreeSplit.insertAfter(prev, fromTextNode(pbNode)); - if (pbNode.hasInsPrevId()) { + if (pbNode.insPrevId) { current.setInsPrev( - rgaTreeSplit.findNode(fromTextNodeID(pbNode.getInsPrevId()!)), + rgaTreeSplit.findNode(fromTextNodeID(pbNode.insPrevId!)), ); } prev = current; } - const text = new CRDTText( - rgaTreeSplit, - fromTimeTicket(pbText.getCreatedAt())!, - ); - text.setMovedAt(fromTimeTicket(pbText.getMovedAt())); - text.setRemovedAt(fromTimeTicket(pbText.getRemovedAt())); + const text = new CRDTText(rgaTreeSplit, fromTimeTicket(pbText.createdAt)!); + text.setMovedAt(fromTimeTicket(pbText.movedAt)); + text.setRemovedAt(fromTimeTicket(pbText.removedAt)); return text; } /** * `fromCounter` converts the given Protobuf format to model format. */ -function fromCounter(pbCounter: PbJSONElement.Counter): CRDTCounter { +function fromCounter(pbCounter: PbJSONElement_Counter): CRDTCounter { const counter = CRDTCounter.create( - fromCounterType(pbCounter.getType()), + fromCounterType(pbCounter.type), CRDTCounter.valueFromBytes( - fromCounterType(pbCounter.getType()), - pbCounter.getValue_asU8(), + fromCounterType(pbCounter.type), + pbCounter.value, ), - fromTimeTicket(pbCounter.getCreatedAt())!, + fromTimeTicket(pbCounter.createdAt)!, ); - counter.setMovedAt(fromTimeTicket(pbCounter.getMovedAt())); - counter.setRemovedAt(fromTimeTicket(pbCounter.getRemovedAt())); + counter.setMovedAt(fromTimeTicket(pbCounter.movedAt)); + counter.setRemovedAt(fromTimeTicket(pbCounter.removedAt)); return counter; } /** * `fromTree` converts the given Protobuf format to model format. */ -function fromTree(pbTree: PbJSONElement.Tree): CRDTTree { - const root = fromTreeNodes(pbTree.getNodesList()); - return CRDTTree.create(root!, fromTimeTicket(pbTree.getCreatedAt())!); +function fromTree(pbTree: PbJSONElement_Tree): CRDTTree { + const root = fromTreeNodes(pbTree.nodes); + return CRDTTree.create(root!, fromTimeTicket(pbTree.createdAt)!); } /** * `fromElement` converts the given Protobuf format to model format. */ function fromElement(pbElement: PbJSONElement): CRDTElement { - if (pbElement.hasJsonObject()) { - return fromObject(pbElement.getJsonObject()!); - } else if (pbElement.hasJsonArray()) { - return fromArray(pbElement.getJsonArray()!); - } else if (pbElement.hasPrimitive()) { - return fromPrimitive(pbElement.getPrimitive()!); - } else if (pbElement.hasText()) { - return fromText(pbElement.getText()!); - } else if (pbElement.hasCounter()) { - return fromCounter(pbElement.getCounter()!); - } else if (pbElement.hasTree()) { - return fromTree(pbElement.getTree()!); + if (pbElement.body.case === 'jsonObject') { + return fromObject(pbElement.body.value!); + } else if (pbElement.body.case === 'jsonArray') { + return fromArray(pbElement.body.value!); + } else if (pbElement.body.case === 'primitive') { + return fromPrimitive(pbElement.body.value!); + } else if (pbElement.body.case === 'text') { + return fromText(pbElement.body.value!); + } else if (pbElement.body.case === 'counter') { + return fromCounter(pbElement.body.value!); + } else if (pbElement.body.case === 'tree') { + return fromTree(pbElement.body.value!); } else { throw new YorkieError(Code.Unimplemented, `unimplemented element`); } @@ -1346,10 +1382,10 @@ function bytesToSnapshot

( }; } - const snapshot = PbSnapshot.deserializeBinary(bytes); + const snapshot = PbSnapshot.fromBinary(bytes); return { - root: fromElement(snapshot.getRoot()!) as CRDTObject, - presences: fromPresences

(snapshot.getPresencesMap()), + root: fromElement(snapshot.root!) as CRDTObject, + presences: fromPresences

(snapshot.presences), }; } @@ -1361,15 +1397,15 @@ function bytesToObject(bytes?: Uint8Array): CRDTObject { throw new Error('bytes is empty'); } - const pbElement = PbJSONElement.deserializeBinary(bytes); - return fromObject(pbElement.getJsonObject()!); + const pbElement = PbJSONElement.fromBinary(bytes); + return fromObject(pbElement.body.value! as PbJSONElement_JSONObject); } /** * `objectToBytes` converts the given JSONObject to byte array. */ function objectToBytes(obj: CRDTObject): Uint8Array { - return toElement(obj).serializeBinary(); + return toElement(obj).toBinary(); } /** @@ -1380,15 +1416,15 @@ function bytesToArray(bytes?: Uint8Array): CRDTArray { throw new Error('bytes is empty'); } - const pbElement = PbJSONElement.deserializeBinary(bytes); - return fromArray(pbElement.getJsonArray()!); + const pbElement = PbJSONElement.fromBinary(bytes); + return fromArray(pbElement.body.value! as PbJSONElement_JSONArray); } /** * `arrayToBytes` converts the given CRDTArray to bytes. */ function arrayToBytes(array: CRDTArray): Uint8Array { - return toArray(array).serializeBinary(); + return toArray(array).toBinary(); } /** @@ -1399,15 +1435,15 @@ function bytesToTree(bytes?: Uint8Array): CRDTTree { throw new Error('bytes is empty'); } - const pbElement = PbJSONElement.deserializeBinary(bytes); - return fromTree(pbElement.getTree()!); + const pbElement = PbJSONElement.fromBinary(bytes); + return fromTree(pbElement.body.value! as PbJSONElement_Tree); } /** * `treeToBytes` converts the given tree to bytes. */ function treeToBytes(tree: CRDTTree): Uint8Array { - return toTree(tree).serializeBinary(); + return toTree(tree).toBinary(); } /** diff --git a/src/api/yorkie/v1/resources.proto b/src/api/yorkie/v1/resources.proto index ad27ca5c8..b98bd59bc 100644 --- a/src/api/yorkie/v1/resources.proto +++ b/src/api/yorkie/v1/resources.proto @@ -20,7 +20,7 @@ package yorkie.v1; import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; -option go_package = ".;v1"; +option go_package = "github.com/yorkie-team/yorkie/api/yorkie/v1;v1"; option java_multiple_files = true; option java_package = "dev.yorkie.api.v1"; diff --git a/src/api/yorkie/v1/resources_pb.d.ts b/src/api/yorkie/v1/resources_pb.d.ts index c5f96d0fd..6daefb702 100644 --- a/src/api/yorkie/v1/resources_pb.d.ts +++ b/src/api/yorkie/v1/resources_pb.d.ts @@ -1,1644 +1,1897 @@ -import * as jspb from 'google-protobuf' +// +// Copyright 2022 The Yorkie Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v1.6.0 with parameter "target=js+dts,js_import_style=legacy_commonjs" +// @generated from file src/api/yorkie/v1/resources.proto (package yorkie.v1, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage, Timestamp } from "@bufbuild/protobuf"; +import { Message, proto3 } from "@bufbuild/protobuf"; + +/** + * @generated from enum yorkie.v1.ValueType + */ +export declare enum ValueType { + /** + * @generated from enum value: VALUE_TYPE_NULL = 0; + */ + NULL = 0, + + /** + * @generated from enum value: VALUE_TYPE_BOOLEAN = 1; + */ + BOOLEAN = 1, + + /** + * @generated from enum value: VALUE_TYPE_INTEGER = 2; + */ + INTEGER = 2, + + /** + * @generated from enum value: VALUE_TYPE_LONG = 3; + */ + LONG = 3, + + /** + * @generated from enum value: VALUE_TYPE_DOUBLE = 4; + */ + DOUBLE = 4, + + /** + * @generated from enum value: VALUE_TYPE_STRING = 5; + */ + STRING = 5, + + /** + * @generated from enum value: VALUE_TYPE_BYTES = 6; + */ + BYTES = 6, + + /** + * @generated from enum value: VALUE_TYPE_DATE = 7; + */ + DATE = 7, + + /** + * @generated from enum value: VALUE_TYPE_JSON_OBJECT = 8; + */ + JSON_OBJECT = 8, + + /** + * @generated from enum value: VALUE_TYPE_JSON_ARRAY = 9; + */ + JSON_ARRAY = 9, + + /** + * @generated from enum value: VALUE_TYPE_TEXT = 10; + */ + TEXT = 10, + + /** + * @generated from enum value: VALUE_TYPE_INTEGER_CNT = 11; + */ + INTEGER_CNT = 11, + + /** + * @generated from enum value: VALUE_TYPE_LONG_CNT = 12; + */ + LONG_CNT = 12, + + /** + * @generated from enum value: VALUE_TYPE_TREE = 13; + */ + TREE = 13, +} -import * as google_protobuf_timestamp_pb from 'google-protobuf/google/protobuf/timestamp_pb'; -import * as google_protobuf_wrappers_pb from 'google-protobuf/google/protobuf/wrappers_pb'; +/** + * @generated from enum yorkie.v1.DocEventType + */ +export declare enum DocEventType { + /** + * @generated from enum value: DOC_EVENT_TYPE_DOCUMENT_CHANGED = 0; + */ + DOCUMENT_CHANGED = 0, + + /** + * @generated from enum value: DOC_EVENT_TYPE_DOCUMENT_WATCHED = 1; + */ + DOCUMENT_WATCHED = 1, + + /** + * @generated from enum value: DOC_EVENT_TYPE_DOCUMENT_UNWATCHED = 2; + */ + DOCUMENT_UNWATCHED = 2, + + /** + * @generated from enum value: DOC_EVENT_TYPE_DOCUMENT_BROADCAST = 3; + */ + DOCUMENT_BROADCAST = 3, +} +/** + * /////////////////////////////////////// + * Messages for Snapshot // + * /////////////////////////////////////// + * + * @generated from message yorkie.v1.Snapshot + */ +export declare class Snapshot extends Message { + /** + * @generated from field: yorkie.v1.JSONElement root = 1; + */ + root?: JSONElement; -export class Snapshot extends jspb.Message { - getRoot(): JSONElement | undefined; - setRoot(value?: JSONElement): Snapshot; - hasRoot(): boolean; - clearRoot(): Snapshot; + /** + * @generated from field: map presences = 2; + */ + presences: { [key: string]: Presence }; - getPresencesMap(): jspb.Map; - clearPresencesMap(): Snapshot; + constructor(data?: PartialMessage); - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Snapshot.AsObject; - static toObject(includeInstance: boolean, msg: Snapshot): Snapshot.AsObject; - static serializeBinaryToWriter(message: Snapshot, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Snapshot; - static deserializeBinaryFromReader(message: Snapshot, reader: jspb.BinaryReader): Snapshot; -} + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Snapshot"; + static readonly fields: FieldList; -export namespace Snapshot { - export type AsObject = { - root?: JSONElement.AsObject, - presencesMap: Array<[string, Presence.AsObject]>, - } -} + static fromBinary(bytes: Uint8Array, options?: Partial): Snapshot; -export class ChangePack extends jspb.Message { - getDocumentKey(): string; - setDocumentKey(value: string): ChangePack; - - getCheckpoint(): Checkpoint | undefined; - setCheckpoint(value?: Checkpoint): ChangePack; - hasCheckpoint(): boolean; - clearCheckpoint(): ChangePack; - - getSnapshot(): Uint8Array | string; - getSnapshot_asU8(): Uint8Array; - getSnapshot_asB64(): string; - setSnapshot(value: Uint8Array | string): ChangePack; - - getChangesList(): Array; - setChangesList(value: Array): ChangePack; - clearChangesList(): ChangePack; - addChanges(value?: Change, index?: number): Change; - - getMinSyncedTicket(): TimeTicket | undefined; - setMinSyncedTicket(value?: TimeTicket): ChangePack; - hasMinSyncedTicket(): boolean; - clearMinSyncedTicket(): ChangePack; - - getIsRemoved(): boolean; - setIsRemoved(value: boolean): ChangePack; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): ChangePack.AsObject; - static toObject(includeInstance: boolean, msg: ChangePack): ChangePack.AsObject; - static serializeBinaryToWriter(message: ChangePack, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): ChangePack; - static deserializeBinaryFromReader(message: ChangePack, reader: jspb.BinaryReader): ChangePack; -} + static fromJson(jsonValue: JsonValue, options?: Partial): Snapshot; -export namespace ChangePack { - export type AsObject = { - documentKey: string, - checkpoint?: Checkpoint.AsObject, - snapshot: Uint8Array | string, - changesList: Array, - minSyncedTicket?: TimeTicket.AsObject, - isRemoved: boolean, - } -} + static fromJsonString(jsonString: string, options?: Partial): Snapshot; -export class Change extends jspb.Message { - getId(): ChangeID | undefined; - setId(value?: ChangeID): Change; - hasId(): boolean; - clearId(): Change; - - getMessage(): string; - setMessage(value: string): Change; - - getOperationsList(): Array; - setOperationsList(value: Array): Change; - clearOperationsList(): Change; - addOperations(value?: Operation, index?: number): Operation; - - getPresenceChange(): PresenceChange | undefined; - setPresenceChange(value?: PresenceChange): Change; - hasPresenceChange(): boolean; - clearPresenceChange(): Change; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Change.AsObject; - static toObject(includeInstance: boolean, msg: Change): Change.AsObject; - static serializeBinaryToWriter(message: Change, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Change; - static deserializeBinaryFromReader(message: Change, reader: jspb.BinaryReader): Change; + static equals(a: Snapshot | PlainMessage | undefined, b: Snapshot | PlainMessage | undefined): boolean; } -export namespace Change { - export type AsObject = { - id?: ChangeID.AsObject, - message: string, - operationsList: Array, - presenceChange?: PresenceChange.AsObject, - } -} +/** + * ChangePack is a message that contains all changes that occurred in a document. + * It is used to synchronize changes between clients and servers. + * + * @generated from message yorkie.v1.ChangePack + */ +export declare class ChangePack extends Message { + /** + * @generated from field: string document_key = 1; + */ + documentKey: string; -export class ChangeID extends jspb.Message { - getClientSeq(): number; - setClientSeq(value: number): ChangeID; + /** + * @generated from field: yorkie.v1.Checkpoint checkpoint = 2; + */ + checkpoint?: Checkpoint; - getServerSeq(): string; - setServerSeq(value: string): ChangeID; + /** + * @generated from field: bytes snapshot = 3; + */ + snapshot: Uint8Array; - getLamport(): string; - setLamport(value: string): ChangeID; + /** + * @generated from field: repeated yorkie.v1.Change changes = 4; + */ + changes: Change[]; - getActorId(): Uint8Array | string; - getActorId_asU8(): Uint8Array; - getActorId_asB64(): string; - setActorId(value: Uint8Array | string): ChangeID; + /** + * @generated from field: yorkie.v1.TimeTicket min_synced_ticket = 5; + */ + minSyncedTicket?: TimeTicket; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): ChangeID.AsObject; - static toObject(includeInstance: boolean, msg: ChangeID): ChangeID.AsObject; - static serializeBinaryToWriter(message: ChangeID, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): ChangeID; - static deserializeBinaryFromReader(message: ChangeID, reader: jspb.BinaryReader): ChangeID; -} + /** + * @generated from field: bool is_removed = 6; + */ + isRemoved: boolean; -export namespace ChangeID { - export type AsObject = { - clientSeq: number, - serverSeq: string, - lamport: string, - actorId: Uint8Array | string, - } -} + constructor(data?: PartialMessage); -export class Operation extends jspb.Message { - getSet(): Operation.Set | undefined; - setSet(value?: Operation.Set): Operation; - hasSet(): boolean; - clearSet(): Operation; - - getAdd(): Operation.Add | undefined; - setAdd(value?: Operation.Add): Operation; - hasAdd(): boolean; - clearAdd(): Operation; - - getMove(): Operation.Move | undefined; - setMove(value?: Operation.Move): Operation; - hasMove(): boolean; - clearMove(): Operation; - - getRemove(): Operation.Remove | undefined; - setRemove(value?: Operation.Remove): Operation; - hasRemove(): boolean; - clearRemove(): Operation; - - getEdit(): Operation.Edit | undefined; - setEdit(value?: Operation.Edit): Operation; - hasEdit(): boolean; - clearEdit(): Operation; - - getSelect(): Operation.Select | undefined; - setSelect(value?: Operation.Select): Operation; - hasSelect(): boolean; - clearSelect(): Operation; - - getStyle(): Operation.Style | undefined; - setStyle(value?: Operation.Style): Operation; - hasStyle(): boolean; - clearStyle(): Operation; - - getIncrease(): Operation.Increase | undefined; - setIncrease(value?: Operation.Increase): Operation; - hasIncrease(): boolean; - clearIncrease(): Operation; - - getTreeEdit(): Operation.TreeEdit | undefined; - setTreeEdit(value?: Operation.TreeEdit): Operation; - hasTreeEdit(): boolean; - clearTreeEdit(): Operation; - - getTreeStyle(): Operation.TreeStyle | undefined; - setTreeStyle(value?: Operation.TreeStyle): Operation; - hasTreeStyle(): boolean; - clearTreeStyle(): Operation; - - getBodyCase(): Operation.BodyCase; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Operation.AsObject; - static toObject(includeInstance: boolean, msg: Operation): Operation.AsObject; - static serializeBinaryToWriter(message: Operation, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Operation; - static deserializeBinaryFromReader(message: Operation, reader: jspb.BinaryReader): Operation; -} + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.ChangePack"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): ChangePack; -export namespace Operation { - export type AsObject = { - set?: Operation.Set.AsObject, - add?: Operation.Add.AsObject, - move?: Operation.Move.AsObject, - remove?: Operation.Remove.AsObject, - edit?: Operation.Edit.AsObject, - select?: Operation.Select.AsObject, - style?: Operation.Style.AsObject, - increase?: Operation.Increase.AsObject, - treeEdit?: Operation.TreeEdit.AsObject, - treeStyle?: Operation.TreeStyle.AsObject, - } - - export class Set extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Set; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Set; - - getKey(): string; - setKey(value: string): Set; - - getValue(): JSONElementSimple | undefined; - setValue(value?: JSONElementSimple): Set; - hasValue(): boolean; - clearValue(): Set; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Set; - hasExecutedAt(): boolean; - clearExecutedAt(): Set; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Set.AsObject; - static toObject(includeInstance: boolean, msg: Set): Set.AsObject; - static serializeBinaryToWriter(message: Set, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Set; - static deserializeBinaryFromReader(message: Set, reader: jspb.BinaryReader): Set; - } - - export namespace Set { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - key: string, - value?: JSONElementSimple.AsObject, - executedAt?: TimeTicket.AsObject, - } - } - - - export class Add extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Add; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Add; - - getPrevCreatedAt(): TimeTicket | undefined; - setPrevCreatedAt(value?: TimeTicket): Add; - hasPrevCreatedAt(): boolean; - clearPrevCreatedAt(): Add; - - getValue(): JSONElementSimple | undefined; - setValue(value?: JSONElementSimple): Add; - hasValue(): boolean; - clearValue(): Add; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Add; - hasExecutedAt(): boolean; - clearExecutedAt(): Add; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Add.AsObject; - static toObject(includeInstance: boolean, msg: Add): Add.AsObject; - static serializeBinaryToWriter(message: Add, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Add; - static deserializeBinaryFromReader(message: Add, reader: jspb.BinaryReader): Add; - } - - export namespace Add { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - prevCreatedAt?: TimeTicket.AsObject, - value?: JSONElementSimple.AsObject, - executedAt?: TimeTicket.AsObject, - } - } - - - export class Move extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Move; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Move; - - getPrevCreatedAt(): TimeTicket | undefined; - setPrevCreatedAt(value?: TimeTicket): Move; - hasPrevCreatedAt(): boolean; - clearPrevCreatedAt(): Move; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): Move; - hasCreatedAt(): boolean; - clearCreatedAt(): Move; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Move; - hasExecutedAt(): boolean; - clearExecutedAt(): Move; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Move.AsObject; - static toObject(includeInstance: boolean, msg: Move): Move.AsObject; - static serializeBinaryToWriter(message: Move, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Move; - static deserializeBinaryFromReader(message: Move, reader: jspb.BinaryReader): Move; - } - - export namespace Move { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - prevCreatedAt?: TimeTicket.AsObject, - createdAt?: TimeTicket.AsObject, - executedAt?: TimeTicket.AsObject, - } - } - - - export class Remove extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Remove; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Remove; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): Remove; - hasCreatedAt(): boolean; - clearCreatedAt(): Remove; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Remove; - hasExecutedAt(): boolean; - clearExecutedAt(): Remove; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Remove.AsObject; - static toObject(includeInstance: boolean, msg: Remove): Remove.AsObject; - static serializeBinaryToWriter(message: Remove, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Remove; - static deserializeBinaryFromReader(message: Remove, reader: jspb.BinaryReader): Remove; - } - - export namespace Remove { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - createdAt?: TimeTicket.AsObject, - executedAt?: TimeTicket.AsObject, - } - } - - - export class Edit extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Edit; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Edit; - - getFrom(): TextNodePos | undefined; - setFrom(value?: TextNodePos): Edit; - hasFrom(): boolean; - clearFrom(): Edit; - - getTo(): TextNodePos | undefined; - setTo(value?: TextNodePos): Edit; - hasTo(): boolean; - clearTo(): Edit; - - getCreatedAtMapByActorMap(): jspb.Map; - clearCreatedAtMapByActorMap(): Edit; - - getContent(): string; - setContent(value: string): Edit; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Edit; - hasExecutedAt(): boolean; - clearExecutedAt(): Edit; - - getAttributesMap(): jspb.Map; - clearAttributesMap(): Edit; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Edit.AsObject; - static toObject(includeInstance: boolean, msg: Edit): Edit.AsObject; - static serializeBinaryToWriter(message: Edit, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Edit; - static deserializeBinaryFromReader(message: Edit, reader: jspb.BinaryReader): Edit; - } - - export namespace Edit { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - from?: TextNodePos.AsObject, - to?: TextNodePos.AsObject, - createdAtMapByActorMap: Array<[string, TimeTicket.AsObject]>, - content: string, - executedAt?: TimeTicket.AsObject, - attributesMap: Array<[string, string]>, - } - } - - - export class Select extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Select; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Select; - - getFrom(): TextNodePos | undefined; - setFrom(value?: TextNodePos): Select; - hasFrom(): boolean; - clearFrom(): Select; - - getTo(): TextNodePos | undefined; - setTo(value?: TextNodePos): Select; - hasTo(): boolean; - clearTo(): Select; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Select; - hasExecutedAt(): boolean; - clearExecutedAt(): Select; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Select.AsObject; - static toObject(includeInstance: boolean, msg: Select): Select.AsObject; - static serializeBinaryToWriter(message: Select, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Select; - static deserializeBinaryFromReader(message: Select, reader: jspb.BinaryReader): Select; - } - - export namespace Select { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - from?: TextNodePos.AsObject, - to?: TextNodePos.AsObject, - executedAt?: TimeTicket.AsObject, - } - } - - - export class Style extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Style; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Style; - - getFrom(): TextNodePos | undefined; - setFrom(value?: TextNodePos): Style; - hasFrom(): boolean; - clearFrom(): Style; - - getTo(): TextNodePos | undefined; - setTo(value?: TextNodePos): Style; - hasTo(): boolean; - clearTo(): Style; - - getAttributesMap(): jspb.Map; - clearAttributesMap(): Style; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Style; - hasExecutedAt(): boolean; - clearExecutedAt(): Style; - - getCreatedAtMapByActorMap(): jspb.Map; - clearCreatedAtMapByActorMap(): Style; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Style.AsObject; - static toObject(includeInstance: boolean, msg: Style): Style.AsObject; - static serializeBinaryToWriter(message: Style, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Style; - static deserializeBinaryFromReader(message: Style, reader: jspb.BinaryReader): Style; - } - - export namespace Style { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - from?: TextNodePos.AsObject, - to?: TextNodePos.AsObject, - attributesMap: Array<[string, string]>, - executedAt?: TimeTicket.AsObject, - createdAtMapByActorMap: Array<[string, TimeTicket.AsObject]>, - } - } - - - export class Increase extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): Increase; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): Increase; - - getValue(): JSONElementSimple | undefined; - setValue(value?: JSONElementSimple): Increase; - hasValue(): boolean; - clearValue(): Increase; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): Increase; - hasExecutedAt(): boolean; - clearExecutedAt(): Increase; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Increase.AsObject; - static toObject(includeInstance: boolean, msg: Increase): Increase.AsObject; - static serializeBinaryToWriter(message: Increase, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Increase; - static deserializeBinaryFromReader(message: Increase, reader: jspb.BinaryReader): Increase; - } - - export namespace Increase { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - value?: JSONElementSimple.AsObject, - executedAt?: TimeTicket.AsObject, - } - } - - - export class TreeEdit extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): TreeEdit; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): TreeEdit; - - getFrom(): TreePos | undefined; - setFrom(value?: TreePos): TreeEdit; - hasFrom(): boolean; - clearFrom(): TreeEdit; - - getTo(): TreePos | undefined; - setTo(value?: TreePos): TreeEdit; - hasTo(): boolean; - clearTo(): TreeEdit; - - getCreatedAtMapByActorMap(): jspb.Map; - clearCreatedAtMapByActorMap(): TreeEdit; - - getContentsList(): Array; - setContentsList(value: Array): TreeEdit; - clearContentsList(): TreeEdit; - addContents(value?: TreeNodes, index?: number): TreeNodes; - - getSplitLevel(): number; - setSplitLevel(value: number): TreeEdit; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): TreeEdit; - hasExecutedAt(): boolean; - clearExecutedAt(): TreeEdit; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TreeEdit.AsObject; - static toObject(includeInstance: boolean, msg: TreeEdit): TreeEdit.AsObject; - static serializeBinaryToWriter(message: TreeEdit, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TreeEdit; - static deserializeBinaryFromReader(message: TreeEdit, reader: jspb.BinaryReader): TreeEdit; - } - - export namespace TreeEdit { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - from?: TreePos.AsObject, - to?: TreePos.AsObject, - createdAtMapByActorMap: Array<[string, TimeTicket.AsObject]>, - contentsList: Array, - splitLevel: number, - executedAt?: TimeTicket.AsObject, - } - } - - - export class TreeStyle extends jspb.Message { - getParentCreatedAt(): TimeTicket | undefined; - setParentCreatedAt(value?: TimeTicket): TreeStyle; - hasParentCreatedAt(): boolean; - clearParentCreatedAt(): TreeStyle; - - getFrom(): TreePos | undefined; - setFrom(value?: TreePos): TreeStyle; - hasFrom(): boolean; - clearFrom(): TreeStyle; - - getTo(): TreePos | undefined; - setTo(value?: TreePos): TreeStyle; - hasTo(): boolean; - clearTo(): TreeStyle; - - getAttributesMap(): jspb.Map; - clearAttributesMap(): TreeStyle; - - getExecutedAt(): TimeTicket | undefined; - setExecutedAt(value?: TimeTicket): TreeStyle; - hasExecutedAt(): boolean; - clearExecutedAt(): TreeStyle; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TreeStyle.AsObject; - static toObject(includeInstance: boolean, msg: TreeStyle): TreeStyle.AsObject; - static serializeBinaryToWriter(message: TreeStyle, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TreeStyle; - static deserializeBinaryFromReader(message: TreeStyle, reader: jspb.BinaryReader): TreeStyle; - } - - export namespace TreeStyle { - export type AsObject = { - parentCreatedAt?: TimeTicket.AsObject, - from?: TreePos.AsObject, - to?: TreePos.AsObject, - attributesMap: Array<[string, string]>, - executedAt?: TimeTicket.AsObject, - } - } - - - export enum BodyCase { - BODY_NOT_SET = 0, - SET = 1, - ADD = 2, - MOVE = 3, - REMOVE = 4, - EDIT = 5, - SELECT = 6, - STYLE = 7, - INCREASE = 8, - TREE_EDIT = 9, - TREE_STYLE = 10, - } + static fromJson(jsonValue: JsonValue, options?: Partial): ChangePack; + + static fromJsonString(jsonString: string, options?: Partial): ChangePack; + + static equals(a: ChangePack | PlainMessage | undefined, b: ChangePack | PlainMessage | undefined): boolean; } -export class JSONElementSimple extends jspb.Message { - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): JSONElementSimple; - hasCreatedAt(): boolean; - clearCreatedAt(): JSONElementSimple; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): JSONElementSimple; - hasMovedAt(): boolean; - clearMovedAt(): JSONElementSimple; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): JSONElementSimple; - hasRemovedAt(): boolean; - clearRemovedAt(): JSONElementSimple; - - getType(): ValueType; - setType(value: ValueType): JSONElementSimple; - - getValue(): Uint8Array | string; - getValue_asU8(): Uint8Array; - getValue_asB64(): string; - setValue(value: Uint8Array | string): JSONElementSimple; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): JSONElementSimple.AsObject; - static toObject(includeInstance: boolean, msg: JSONElementSimple): JSONElementSimple.AsObject; - static serializeBinaryToWriter(message: JSONElementSimple, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): JSONElementSimple; - static deserializeBinaryFromReader(message: JSONElementSimple, reader: jspb.BinaryReader): JSONElementSimple; +/** + * @generated from message yorkie.v1.Change + */ +export declare class Change extends Message { + /** + * @generated from field: yorkie.v1.ChangeID id = 1; + */ + id?: ChangeID; + + /** + * @generated from field: string message = 2; + */ + message: string; + + /** + * @generated from field: repeated yorkie.v1.Operation operations = 3; + */ + operations: Operation[]; + + /** + * @generated from field: yorkie.v1.PresenceChange presence_change = 4; + */ + presenceChange?: PresenceChange; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Change"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Change; + + static fromJson(jsonValue: JsonValue, options?: Partial): Change; + + static fromJsonString(jsonString: string, options?: Partial): Change; + + static equals(a: Change | PlainMessage | undefined, b: Change | PlainMessage | undefined): boolean; } -export namespace JSONElementSimple { - export type AsObject = { - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - type: ValueType, - value: Uint8Array | string, - } +/** + * @generated from message yorkie.v1.ChangeID + */ +export declare class ChangeID extends Message { + /** + * @generated from field: uint32 client_seq = 1; + */ + clientSeq: number; + + /** + * @generated from field: int64 server_seq = 2 [jstype = JS_STRING]; + */ + serverSeq: string; + + /** + * @generated from field: int64 lamport = 3 [jstype = JS_STRING]; + */ + lamport: string; + + /** + * @generated from field: bytes actor_id = 4; + */ + actorId: Uint8Array; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.ChangeID"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): ChangeID; + + static fromJson(jsonValue: JsonValue, options?: Partial): ChangeID; + + static fromJsonString(jsonString: string, options?: Partial): ChangeID; + + static equals(a: ChangeID | PlainMessage | undefined, b: ChangeID | PlainMessage | undefined): boolean; } -export class JSONElement extends jspb.Message { - getJsonObject(): JSONElement.JSONObject | undefined; - setJsonObject(value?: JSONElement.JSONObject): JSONElement; - hasJsonObject(): boolean; - clearJsonObject(): JSONElement; - - getJsonArray(): JSONElement.JSONArray | undefined; - setJsonArray(value?: JSONElement.JSONArray): JSONElement; - hasJsonArray(): boolean; - clearJsonArray(): JSONElement; - - getPrimitive(): JSONElement.Primitive | undefined; - setPrimitive(value?: JSONElement.Primitive): JSONElement; - hasPrimitive(): boolean; - clearPrimitive(): JSONElement; - - getText(): JSONElement.Text | undefined; - setText(value?: JSONElement.Text): JSONElement; - hasText(): boolean; - clearText(): JSONElement; - - getCounter(): JSONElement.Counter | undefined; - setCounter(value?: JSONElement.Counter): JSONElement; - hasCounter(): boolean; - clearCounter(): JSONElement; - - getTree(): JSONElement.Tree | undefined; - setTree(value?: JSONElement.Tree): JSONElement; - hasTree(): boolean; - clearTree(): JSONElement; - - getBodyCase(): JSONElement.BodyCase; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): JSONElement.AsObject; - static toObject(includeInstance: boolean, msg: JSONElement): JSONElement.AsObject; - static serializeBinaryToWriter(message: JSONElement, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): JSONElement; - static deserializeBinaryFromReader(message: JSONElement, reader: jspb.BinaryReader): JSONElement; +/** + * @generated from message yorkie.v1.Operation + */ +export declare class Operation extends Message { + /** + * @generated from oneof yorkie.v1.Operation.body + */ + body: { + /** + * @generated from field: yorkie.v1.Operation.Set set = 1; + */ + value: Operation_Set; + case: "set"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Add add = 2; + */ + value: Operation_Add; + case: "add"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Move move = 3; + */ + value: Operation_Move; + case: "move"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Remove remove = 4; + */ + value: Operation_Remove; + case: "remove"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Edit edit = 5; + */ + value: Operation_Edit; + case: "edit"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Select select = 6; + */ + value: Operation_Select; + case: "select"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Style style = 7; + */ + value: Operation_Style; + case: "style"; + } | { + /** + * @generated from field: yorkie.v1.Operation.Increase increase = 8; + */ + value: Operation_Increase; + case: "increase"; + } | { + /** + * @generated from field: yorkie.v1.Operation.TreeEdit tree_edit = 9; + */ + value: Operation_TreeEdit; + case: "treeEdit"; + } | { + /** + * @generated from field: yorkie.v1.Operation.TreeStyle tree_style = 10; + */ + value: Operation_TreeStyle; + case: "treeStyle"; + } | { case: undefined; value?: undefined }; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation; + + static fromJsonString(jsonString: string, options?: Partial): Operation; + + static equals(a: Operation | PlainMessage | undefined, b: Operation | PlainMessage | undefined): boolean; } -export namespace JSONElement { - export type AsObject = { - jsonObject?: JSONElement.JSONObject.AsObject, - jsonArray?: JSONElement.JSONArray.AsObject, - primitive?: JSONElement.Primitive.AsObject, - text?: JSONElement.Text.AsObject, - counter?: JSONElement.Counter.AsObject, - tree?: JSONElement.Tree.AsObject, - } - - export class JSONObject extends jspb.Message { - getNodesList(): Array; - setNodesList(value: Array): JSONObject; - clearNodesList(): JSONObject; - addNodes(value?: RHTNode, index?: number): RHTNode; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): JSONObject; - hasCreatedAt(): boolean; - clearCreatedAt(): JSONObject; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): JSONObject; - hasMovedAt(): boolean; - clearMovedAt(): JSONObject; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): JSONObject; - hasRemovedAt(): boolean; - clearRemovedAt(): JSONObject; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): JSONObject.AsObject; - static toObject(includeInstance: boolean, msg: JSONObject): JSONObject.AsObject; - static serializeBinaryToWriter(message: JSONObject, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): JSONObject; - static deserializeBinaryFromReader(message: JSONObject, reader: jspb.BinaryReader): JSONObject; - } - - export namespace JSONObject { - export type AsObject = { - nodesList: Array, - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - } - } - - - export class JSONArray extends jspb.Message { - getNodesList(): Array; - setNodesList(value: Array): JSONArray; - clearNodesList(): JSONArray; - addNodes(value?: RGANode, index?: number): RGANode; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): JSONArray; - hasCreatedAt(): boolean; - clearCreatedAt(): JSONArray; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): JSONArray; - hasMovedAt(): boolean; - clearMovedAt(): JSONArray; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): JSONArray; - hasRemovedAt(): boolean; - clearRemovedAt(): JSONArray; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): JSONArray.AsObject; - static toObject(includeInstance: boolean, msg: JSONArray): JSONArray.AsObject; - static serializeBinaryToWriter(message: JSONArray, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): JSONArray; - static deserializeBinaryFromReader(message: JSONArray, reader: jspb.BinaryReader): JSONArray; - } - - export namespace JSONArray { - export type AsObject = { - nodesList: Array, - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - } - } - - - export class Primitive extends jspb.Message { - getType(): ValueType; - setType(value: ValueType): Primitive; - - getValue(): Uint8Array | string; - getValue_asU8(): Uint8Array; - getValue_asB64(): string; - setValue(value: Uint8Array | string): Primitive; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): Primitive; - hasCreatedAt(): boolean; - clearCreatedAt(): Primitive; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): Primitive; - hasMovedAt(): boolean; - clearMovedAt(): Primitive; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): Primitive; - hasRemovedAt(): boolean; - clearRemovedAt(): Primitive; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Primitive.AsObject; - static toObject(includeInstance: boolean, msg: Primitive): Primitive.AsObject; - static serializeBinaryToWriter(message: Primitive, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Primitive; - static deserializeBinaryFromReader(message: Primitive, reader: jspb.BinaryReader): Primitive; - } - - export namespace Primitive { - export type AsObject = { - type: ValueType, - value: Uint8Array | string, - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - } - } - - - export class Text extends jspb.Message { - getNodesList(): Array; - setNodesList(value: Array): Text; - clearNodesList(): Text; - addNodes(value?: TextNode, index?: number): TextNode; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): Text; - hasCreatedAt(): boolean; - clearCreatedAt(): Text; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): Text; - hasMovedAt(): boolean; - clearMovedAt(): Text; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): Text; - hasRemovedAt(): boolean; - clearRemovedAt(): Text; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Text.AsObject; - static toObject(includeInstance: boolean, msg: Text): Text.AsObject; - static serializeBinaryToWriter(message: Text, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Text; - static deserializeBinaryFromReader(message: Text, reader: jspb.BinaryReader): Text; - } - - export namespace Text { - export type AsObject = { - nodesList: Array, - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - } - } - - - export class Counter extends jspb.Message { - getType(): ValueType; - setType(value: ValueType): Counter; - - getValue(): Uint8Array | string; - getValue_asU8(): Uint8Array; - getValue_asB64(): string; - setValue(value: Uint8Array | string): Counter; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): Counter; - hasCreatedAt(): boolean; - clearCreatedAt(): Counter; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): Counter; - hasMovedAt(): boolean; - clearMovedAt(): Counter; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): Counter; - hasRemovedAt(): boolean; - clearRemovedAt(): Counter; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Counter.AsObject; - static toObject(includeInstance: boolean, msg: Counter): Counter.AsObject; - static serializeBinaryToWriter(message: Counter, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Counter; - static deserializeBinaryFromReader(message: Counter, reader: jspb.BinaryReader): Counter; - } - - export namespace Counter { - export type AsObject = { - type: ValueType, - value: Uint8Array | string, - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - } - } - - - export class Tree extends jspb.Message { - getNodesList(): Array; - setNodesList(value: Array): Tree; - clearNodesList(): Tree; - addNodes(value?: TreeNode, index?: number): TreeNode; - - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): Tree; - hasCreatedAt(): boolean; - clearCreatedAt(): Tree; - - getMovedAt(): TimeTicket | undefined; - setMovedAt(value?: TimeTicket): Tree; - hasMovedAt(): boolean; - clearMovedAt(): Tree; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): Tree; - hasRemovedAt(): boolean; - clearRemovedAt(): Tree; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Tree.AsObject; - static toObject(includeInstance: boolean, msg: Tree): Tree.AsObject; - static serializeBinaryToWriter(message: Tree, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Tree; - static deserializeBinaryFromReader(message: Tree, reader: jspb.BinaryReader): Tree; - } - - export namespace Tree { - export type AsObject = { - nodesList: Array, - createdAt?: TimeTicket.AsObject, - movedAt?: TimeTicket.AsObject, - removedAt?: TimeTicket.AsObject, - } - } - - - export enum BodyCase { - BODY_NOT_SET = 0, - JSON_OBJECT = 1, - JSON_ARRAY = 2, - PRIMITIVE = 3, - TEXT = 5, - COUNTER = 6, - TREE = 7, - } +/** + * @generated from message yorkie.v1.Operation.Set + */ +export declare class Operation_Set extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: string key = 2; + */ + key: string; + + /** + * @generated from field: yorkie.v1.JSONElementSimple value = 3; + */ + value?: JSONElementSimple; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 4; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Set"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Set; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Set; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Set; + + static equals(a: Operation_Set | PlainMessage | undefined, b: Operation_Set | PlainMessage | undefined): boolean; } -export class RHTNode extends jspb.Message { - getKey(): string; - setKey(value: string): RHTNode; - - getElement(): JSONElement | undefined; - setElement(value?: JSONElement): RHTNode; - hasElement(): boolean; - clearElement(): RHTNode; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): RHTNode.AsObject; - static toObject(includeInstance: boolean, msg: RHTNode): RHTNode.AsObject; - static serializeBinaryToWriter(message: RHTNode, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): RHTNode; - static deserializeBinaryFromReader(message: RHTNode, reader: jspb.BinaryReader): RHTNode; +/** + * @generated from message yorkie.v1.Operation.Add + */ +export declare class Operation_Add extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket prev_created_at = 2; + */ + prevCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.JSONElementSimple value = 3; + */ + value?: JSONElementSimple; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 4; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Add"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Add; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Add; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Add; + + static equals(a: Operation_Add | PlainMessage | undefined, b: Operation_Add | PlainMessage | undefined): boolean; } -export namespace RHTNode { - export type AsObject = { - key: string, - element?: JSONElement.AsObject, - } +/** + * @generated from message yorkie.v1.Operation.Move + */ +export declare class Operation_Move extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket prev_created_at = 2; + */ + prevCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 3; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 4; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Move"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Move; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Move; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Move; + + static equals(a: Operation_Move | PlainMessage | undefined, b: Operation_Move | PlainMessage | undefined): boolean; } -export class RGANode extends jspb.Message { - getNext(): RGANode | undefined; - setNext(value?: RGANode): RGANode; - hasNext(): boolean; - clearNext(): RGANode; - - getElement(): JSONElement | undefined; - setElement(value?: JSONElement): RGANode; - hasElement(): boolean; - clearElement(): RGANode; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): RGANode.AsObject; - static toObject(includeInstance: boolean, msg: RGANode): RGANode.AsObject; - static serializeBinaryToWriter(message: RGANode, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): RGANode; - static deserializeBinaryFromReader(message: RGANode, reader: jspb.BinaryReader): RGANode; +/** + * @generated from message yorkie.v1.Operation.Remove + */ +export declare class Operation_Remove extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 2; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 3; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Remove"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Remove; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Remove; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Remove; + + static equals(a: Operation_Remove | PlainMessage | undefined, b: Operation_Remove | PlainMessage | undefined): boolean; } -export namespace RGANode { - export type AsObject = { - next?: RGANode.AsObject, - element?: JSONElement.AsObject, - } +/** + * @generated from message yorkie.v1.Operation.Edit + */ +export declare class Operation_Edit extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TextNodePos from = 2; + */ + from?: TextNodePos; + + /** + * @generated from field: yorkie.v1.TextNodePos to = 3; + */ + to?: TextNodePos; + + /** + * @generated from field: map created_at_map_by_actor = 4; + */ + createdAtMapByActor: { [key: string]: TimeTicket }; + + /** + * @generated from field: string content = 5; + */ + content: string; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 6; + */ + executedAt?: TimeTicket; + + /** + * @generated from field: map attributes = 7; + */ + attributes: { [key: string]: string }; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Edit"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Edit; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Edit; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Edit; + + static equals(a: Operation_Edit | PlainMessage | undefined, b: Operation_Edit | PlainMessage | undefined): boolean; } -export class NodeAttr extends jspb.Message { - getValue(): string; - setValue(value: string): NodeAttr; - - getUpdatedAt(): TimeTicket | undefined; - setUpdatedAt(value?: TimeTicket): NodeAttr; - hasUpdatedAt(): boolean; - clearUpdatedAt(): NodeAttr; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): NodeAttr.AsObject; - static toObject(includeInstance: boolean, msg: NodeAttr): NodeAttr.AsObject; - static serializeBinaryToWriter(message: NodeAttr, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): NodeAttr; - static deserializeBinaryFromReader(message: NodeAttr, reader: jspb.BinaryReader): NodeAttr; +/** + * NOTE(hackerwins): Select Operation is not used in the current version. + * In the previous version, it was used to represent selection of Text. + * However, it has been replaced by Presence now. It is retained for backward + * compatibility purposes. + * + * @generated from message yorkie.v1.Operation.Select + */ +export declare class Operation_Select extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TextNodePos from = 2; + */ + from?: TextNodePos; + + /** + * @generated from field: yorkie.v1.TextNodePos to = 3; + */ + to?: TextNodePos; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 4; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Select"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Select; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Select; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Select; + + static equals(a: Operation_Select | PlainMessage | undefined, b: Operation_Select | PlainMessage | undefined): boolean; } -export namespace NodeAttr { - export type AsObject = { - value: string, - updatedAt?: TimeTicket.AsObject, - } +/** + * @generated from message yorkie.v1.Operation.Style + */ +export declare class Operation_Style extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TextNodePos from = 2; + */ + from?: TextNodePos; + + /** + * @generated from field: yorkie.v1.TextNodePos to = 3; + */ + to?: TextNodePos; + + /** + * @generated from field: map attributes = 4; + */ + attributes: { [key: string]: string }; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 5; + */ + executedAt?: TimeTicket; + + /** + * @generated from field: map created_at_map_by_actor = 6; + */ + createdAtMapByActor: { [key: string]: TimeTicket }; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Style"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Style; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Style; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Style; + + static equals(a: Operation_Style | PlainMessage | undefined, b: Operation_Style | PlainMessage | undefined): boolean; } -export class TextNode extends jspb.Message { - getId(): TextNodeID | undefined; - setId(value?: TextNodeID): TextNode; - hasId(): boolean; - clearId(): TextNode; - - getValue(): string; - setValue(value: string): TextNode; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): TextNode; - hasRemovedAt(): boolean; - clearRemovedAt(): TextNode; - - getInsPrevId(): TextNodeID | undefined; - setInsPrevId(value?: TextNodeID): TextNode; - hasInsPrevId(): boolean; - clearInsPrevId(): TextNode; - - getAttributesMap(): jspb.Map; - clearAttributesMap(): TextNode; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TextNode.AsObject; - static toObject(includeInstance: boolean, msg: TextNode): TextNode.AsObject; - static serializeBinaryToWriter(message: TextNode, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TextNode; - static deserializeBinaryFromReader(message: TextNode, reader: jspb.BinaryReader): TextNode; +/** + * @generated from message yorkie.v1.Operation.Increase + */ +export declare class Operation_Increase extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.JSONElementSimple value = 2; + */ + value?: JSONElementSimple; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 3; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.Increase"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_Increase; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_Increase; + + static fromJsonString(jsonString: string, options?: Partial): Operation_Increase; + + static equals(a: Operation_Increase | PlainMessage | undefined, b: Operation_Increase | PlainMessage | undefined): boolean; } -export namespace TextNode { - export type AsObject = { - id?: TextNodeID.AsObject, - value: string, - removedAt?: TimeTicket.AsObject, - insPrevId?: TextNodeID.AsObject, - attributesMap: Array<[string, NodeAttr.AsObject]>, - } +/** + * @generated from message yorkie.v1.Operation.TreeEdit + */ +export declare class Operation_TreeEdit extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TreePos from = 2; + */ + from?: TreePos; + + /** + * @generated from field: yorkie.v1.TreePos to = 3; + */ + to?: TreePos; + + /** + * @generated from field: map created_at_map_by_actor = 4; + */ + createdAtMapByActor: { [key: string]: TimeTicket }; + + /** + * @generated from field: repeated yorkie.v1.TreeNodes contents = 5; + */ + contents: TreeNodes[]; + + /** + * @generated from field: int32 split_level = 7; + */ + splitLevel: number; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 6; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.TreeEdit"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_TreeEdit; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_TreeEdit; + + static fromJsonString(jsonString: string, options?: Partial): Operation_TreeEdit; + + static equals(a: Operation_TreeEdit | PlainMessage | undefined, b: Operation_TreeEdit | PlainMessage | undefined): boolean; } -export class TextNodeID extends jspb.Message { - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): TextNodeID; - hasCreatedAt(): boolean; - clearCreatedAt(): TextNodeID; - - getOffset(): number; - setOffset(value: number): TextNodeID; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TextNodeID.AsObject; - static toObject(includeInstance: boolean, msg: TextNodeID): TextNodeID.AsObject; - static serializeBinaryToWriter(message: TextNodeID, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TextNodeID; - static deserializeBinaryFromReader(message: TextNodeID, reader: jspb.BinaryReader): TextNodeID; +/** + * @generated from message yorkie.v1.Operation.TreeStyle + */ +export declare class Operation_TreeStyle extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; + */ + parentCreatedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TreePos from = 2; + */ + from?: TreePos; + + /** + * @generated from field: yorkie.v1.TreePos to = 3; + */ + to?: TreePos; + + /** + * @generated from field: map attributes = 4; + */ + attributes: { [key: string]: string }; + + /** + * @generated from field: yorkie.v1.TimeTicket executed_at = 5; + */ + executedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Operation.TreeStyle"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Operation_TreeStyle; + + static fromJson(jsonValue: JsonValue, options?: Partial): Operation_TreeStyle; + + static fromJsonString(jsonString: string, options?: Partial): Operation_TreeStyle; + + static equals(a: Operation_TreeStyle | PlainMessage | undefined, b: Operation_TreeStyle | PlainMessage | undefined): boolean; } -export namespace TextNodeID { - export type AsObject = { - createdAt?: TimeTicket.AsObject, - offset: number, - } +/** + * @generated from message yorkie.v1.JSONElementSimple + */ +export declare class JSONElementSimple extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 1; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 2; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 3; + */ + removedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.ValueType type = 4; + */ + type: ValueType; + + /** + * @generated from field: bytes value = 5; + */ + value: Uint8Array; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElementSimple"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElementSimple; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElementSimple; + + static fromJsonString(jsonString: string, options?: Partial): JSONElementSimple; + + static equals(a: JSONElementSimple | PlainMessage | undefined, b: JSONElementSimple | PlainMessage | undefined): boolean; } -export class TreeNode extends jspb.Message { - getId(): TreeNodeID | undefined; - setId(value?: TreeNodeID): TreeNode; - hasId(): boolean; - clearId(): TreeNode; - - getType(): string; - setType(value: string): TreeNode; - - getValue(): string; - setValue(value: string): TreeNode; - - getRemovedAt(): TimeTicket | undefined; - setRemovedAt(value?: TimeTicket): TreeNode; - hasRemovedAt(): boolean; - clearRemovedAt(): TreeNode; - - getInsPrevId(): TreeNodeID | undefined; - setInsPrevId(value?: TreeNodeID): TreeNode; - hasInsPrevId(): boolean; - clearInsPrevId(): TreeNode; - - getInsNextId(): TreeNodeID | undefined; - setInsNextId(value?: TreeNodeID): TreeNode; - hasInsNextId(): boolean; - clearInsNextId(): TreeNode; - - getDepth(): number; - setDepth(value: number): TreeNode; - - getAttributesMap(): jspb.Map; - clearAttributesMap(): TreeNode; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TreeNode.AsObject; - static toObject(includeInstance: boolean, msg: TreeNode): TreeNode.AsObject; - static serializeBinaryToWriter(message: TreeNode, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TreeNode; - static deserializeBinaryFromReader(message: TreeNode, reader: jspb.BinaryReader): TreeNode; +/** + * @generated from message yorkie.v1.JSONElement + */ +export declare class JSONElement extends Message { + /** + * @generated from oneof yorkie.v1.JSONElement.body + */ + body: { + /** + * @generated from field: yorkie.v1.JSONElement.JSONObject json_object = 1; + */ + value: JSONElement_JSONObject; + case: "jsonObject"; + } | { + /** + * @generated from field: yorkie.v1.JSONElement.JSONArray json_array = 2; + */ + value: JSONElement_JSONArray; + case: "jsonArray"; + } | { + /** + * @generated from field: yorkie.v1.JSONElement.Primitive primitive = 3; + */ + value: JSONElement_Primitive; + case: "primitive"; + } | { + /** + * @generated from field: yorkie.v1.JSONElement.Text text = 5; + */ + value: JSONElement_Text; + case: "text"; + } | { + /** + * @generated from field: yorkie.v1.JSONElement.Counter counter = 6; + */ + value: JSONElement_Counter; + case: "counter"; + } | { + /** + * @generated from field: yorkie.v1.JSONElement.Tree tree = 7; + */ + value: JSONElement_Tree; + case: "tree"; + } | { case: undefined; value?: undefined }; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement; + + static equals(a: JSONElement | PlainMessage | undefined, b: JSONElement | PlainMessage | undefined): boolean; } -export namespace TreeNode { - export type AsObject = { - id?: TreeNodeID.AsObject, - type: string, - value: string, - removedAt?: TimeTicket.AsObject, - insPrevId?: TreeNodeID.AsObject, - insNextId?: TreeNodeID.AsObject, - depth: number, - attributesMap: Array<[string, NodeAttr.AsObject]>, - } +/** + * @generated from message yorkie.v1.JSONElement.JSONObject + */ +export declare class JSONElement_JSONObject extends Message { + /** + * @generated from field: repeated yorkie.v1.RHTNode nodes = 1; + */ + nodes: RHTNode[]; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 2; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 3; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 4; + */ + removedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement.JSONObject"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement_JSONObject; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement_JSONObject; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement_JSONObject; + + static equals(a: JSONElement_JSONObject | PlainMessage | undefined, b: JSONElement_JSONObject | PlainMessage | undefined): boolean; } -export class TreeNodes extends jspb.Message { - getContentList(): Array; - setContentList(value: Array): TreeNodes; - clearContentList(): TreeNodes; - addContent(value?: TreeNode, index?: number): TreeNode; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TreeNodes.AsObject; - static toObject(includeInstance: boolean, msg: TreeNodes): TreeNodes.AsObject; - static serializeBinaryToWriter(message: TreeNodes, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TreeNodes; - static deserializeBinaryFromReader(message: TreeNodes, reader: jspb.BinaryReader): TreeNodes; +/** + * @generated from message yorkie.v1.JSONElement.JSONArray + */ +export declare class JSONElement_JSONArray extends Message { + /** + * @generated from field: repeated yorkie.v1.RGANode nodes = 1; + */ + nodes: RGANode[]; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 2; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 3; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 4; + */ + removedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement.JSONArray"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement_JSONArray; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement_JSONArray; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement_JSONArray; + + static equals(a: JSONElement_JSONArray | PlainMessage | undefined, b: JSONElement_JSONArray | PlainMessage | undefined): boolean; } -export namespace TreeNodes { - export type AsObject = { - contentList: Array, - } +/** + * @generated from message yorkie.v1.JSONElement.Primitive + */ +export declare class JSONElement_Primitive extends Message { + /** + * @generated from field: yorkie.v1.ValueType type = 1; + */ + type: ValueType; + + /** + * @generated from field: bytes value = 2; + */ + value: Uint8Array; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 3; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 4; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 5; + */ + removedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement.Primitive"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement_Primitive; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement_Primitive; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement_Primitive; + + static equals(a: JSONElement_Primitive | PlainMessage | undefined, b: JSONElement_Primitive | PlainMessage | undefined): boolean; } -export class TreeNodeID extends jspb.Message { - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): TreeNodeID; - hasCreatedAt(): boolean; - clearCreatedAt(): TreeNodeID; - - getOffset(): number; - setOffset(value: number): TreeNodeID; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TreeNodeID.AsObject; - static toObject(includeInstance: boolean, msg: TreeNodeID): TreeNodeID.AsObject; - static serializeBinaryToWriter(message: TreeNodeID, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TreeNodeID; - static deserializeBinaryFromReader(message: TreeNodeID, reader: jspb.BinaryReader): TreeNodeID; +/** + * @generated from message yorkie.v1.JSONElement.Text + */ +export declare class JSONElement_Text extends Message { + /** + * @generated from field: repeated yorkie.v1.TextNode nodes = 1; + */ + nodes: TextNode[]; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 2; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 3; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 4; + */ + removedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement.Text"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement_Text; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement_Text; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement_Text; + + static equals(a: JSONElement_Text | PlainMessage | undefined, b: JSONElement_Text | PlainMessage | undefined): boolean; } -export namespace TreeNodeID { - export type AsObject = { - createdAt?: TimeTicket.AsObject, - offset: number, - } +/** + * @generated from message yorkie.v1.JSONElement.Counter + */ +export declare class JSONElement_Counter extends Message { + /** + * @generated from field: yorkie.v1.ValueType type = 1; + */ + type: ValueType; + + /** + * @generated from field: bytes value = 2; + */ + value: Uint8Array; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 3; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 4; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 5; + */ + removedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement.Counter"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement_Counter; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement_Counter; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement_Counter; + + static equals(a: JSONElement_Counter | PlainMessage | undefined, b: JSONElement_Counter | PlainMessage | undefined): boolean; } -export class TreePos extends jspb.Message { - getParentId(): TreeNodeID | undefined; - setParentId(value?: TreeNodeID): TreePos; - hasParentId(): boolean; - clearParentId(): TreePos; - - getLeftSiblingId(): TreeNodeID | undefined; - setLeftSiblingId(value?: TreeNodeID): TreePos; - hasLeftSiblingId(): boolean; - clearLeftSiblingId(): TreePos; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TreePos.AsObject; - static toObject(includeInstance: boolean, msg: TreePos): TreePos.AsObject; - static serializeBinaryToWriter(message: TreePos, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TreePos; - static deserializeBinaryFromReader(message: TreePos, reader: jspb.BinaryReader): TreePos; +/** + * @generated from message yorkie.v1.JSONElement.Tree + */ +export declare class JSONElement_Tree extends Message { + /** + * @generated from field: repeated yorkie.v1.TreeNode nodes = 1; + */ + nodes: TreeNode[]; + + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 2; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket moved_at = 3; + */ + movedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 4; + */ + removedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.JSONElement.Tree"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): JSONElement_Tree; + + static fromJson(jsonValue: JsonValue, options?: Partial): JSONElement_Tree; + + static fromJsonString(jsonString: string, options?: Partial): JSONElement_Tree; + + static equals(a: JSONElement_Tree | PlainMessage | undefined, b: JSONElement_Tree | PlainMessage | undefined): boolean; } -export namespace TreePos { - export type AsObject = { - parentId?: TreeNodeID.AsObject, - leftSiblingId?: TreeNodeID.AsObject, - } +/** + * @generated from message yorkie.v1.RHTNode + */ +export declare class RHTNode extends Message { + /** + * @generated from field: string key = 1; + */ + key: string; + + /** + * @generated from field: yorkie.v1.JSONElement element = 2; + */ + element?: JSONElement; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.RHTNode"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): RHTNode; + + static fromJson(jsonValue: JsonValue, options?: Partial): RHTNode; + + static fromJsonString(jsonString: string, options?: Partial): RHTNode; + + static equals(a: RHTNode | PlainMessage | undefined, b: RHTNode | PlainMessage | undefined): boolean; } -export class User extends jspb.Message { - getId(): string; - setId(value: string): User; +/** + * @generated from message yorkie.v1.RGANode + */ +export declare class RGANode extends Message { + /** + * @generated from field: yorkie.v1.RGANode next = 1; + */ + next?: RGANode; + + /** + * @generated from field: yorkie.v1.JSONElement element = 2; + */ + element?: JSONElement; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.RGANode"; + static readonly fields: FieldList; - getUsername(): string; - setUsername(value: string): User; + static fromBinary(bytes: Uint8Array, options?: Partial): RGANode; - getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined; - setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): User; - hasCreatedAt(): boolean; - clearCreatedAt(): User; + static fromJson(jsonValue: JsonValue, options?: Partial): RGANode; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): User.AsObject; - static toObject(includeInstance: boolean, msg: User): User.AsObject; - static serializeBinaryToWriter(message: User, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): User; - static deserializeBinaryFromReader(message: User, reader: jspb.BinaryReader): User; + static fromJsonString(jsonString: string, options?: Partial): RGANode; + + static equals(a: RGANode | PlainMessage | undefined, b: RGANode | PlainMessage | undefined): boolean; } -export namespace User { - export type AsObject = { - id: string, - username: string, - createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject, - } +/** + * @generated from message yorkie.v1.NodeAttr + */ +export declare class NodeAttr extends Message { + /** + * @generated from field: string value = 1; + */ + value: string; + + /** + * @generated from field: yorkie.v1.TimeTicket updated_at = 2; + */ + updatedAt?: TimeTicket; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.NodeAttr"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): NodeAttr; + + static fromJson(jsonValue: JsonValue, options?: Partial): NodeAttr; + + static fromJsonString(jsonString: string, options?: Partial): NodeAttr; + + static equals(a: NodeAttr | PlainMessage | undefined, b: NodeAttr | PlainMessage | undefined): boolean; } -export class Project extends jspb.Message { - getId(): string; - setId(value: string): Project; +/** + * @generated from message yorkie.v1.TextNode + */ +export declare class TextNode extends Message { + /** + * @generated from field: yorkie.v1.TextNodeID id = 1; + */ + id?: TextNodeID; - getName(): string; - setName(value: string): Project; + /** + * @generated from field: string value = 2; + */ + value: string; - getPublicKey(): string; - setPublicKey(value: string): Project; + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 3; + */ + removedAt?: TimeTicket; - getSecretKey(): string; - setSecretKey(value: string): Project; + /** + * @generated from field: yorkie.v1.TextNodeID ins_prev_id = 4; + */ + insPrevId?: TextNodeID; - getAuthWebhookUrl(): string; - setAuthWebhookUrl(value: string): Project; + /** + * @generated from field: map attributes = 5; + */ + attributes: { [key: string]: NodeAttr }; - getAuthWebhookMethodsList(): Array; - setAuthWebhookMethodsList(value: Array): Project; - clearAuthWebhookMethodsList(): Project; - addAuthWebhookMethods(value: string, index?: number): Project; + constructor(data?: PartialMessage); - getClientDeactivateThreshold(): string; - setClientDeactivateThreshold(value: string): Project; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TextNode"; + static readonly fields: FieldList; - getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined; - setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): Project; - hasCreatedAt(): boolean; - clearCreatedAt(): Project; + static fromBinary(bytes: Uint8Array, options?: Partial): TextNode; - getUpdatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined; - setUpdatedAt(value?: google_protobuf_timestamp_pb.Timestamp): Project; - hasUpdatedAt(): boolean; - clearUpdatedAt(): Project; + static fromJson(jsonValue: JsonValue, options?: Partial): TextNode; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Project.AsObject; - static toObject(includeInstance: boolean, msg: Project): Project.AsObject; - static serializeBinaryToWriter(message: Project, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Project; - static deserializeBinaryFromReader(message: Project, reader: jspb.BinaryReader): Project; -} + static fromJsonString(jsonString: string, options?: Partial): TextNode; -export namespace Project { - export type AsObject = { - id: string, - name: string, - publicKey: string, - secretKey: string, - authWebhookUrl: string, - authWebhookMethodsList: Array, - clientDeactivateThreshold: string, - createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject, - updatedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject, - } + static equals(a: TextNode | PlainMessage | undefined, b: TextNode | PlainMessage | undefined): boolean; } -export class UpdatableProjectFields extends jspb.Message { - getName(): google_protobuf_wrappers_pb.StringValue | undefined; - setName(value?: google_protobuf_wrappers_pb.StringValue): UpdatableProjectFields; - hasName(): boolean; - clearName(): UpdatableProjectFields; - - getAuthWebhookUrl(): google_protobuf_wrappers_pb.StringValue | undefined; - setAuthWebhookUrl(value?: google_protobuf_wrappers_pb.StringValue): UpdatableProjectFields; - hasAuthWebhookUrl(): boolean; - clearAuthWebhookUrl(): UpdatableProjectFields; - - getAuthWebhookMethods(): UpdatableProjectFields.AuthWebhookMethods | undefined; - setAuthWebhookMethods(value?: UpdatableProjectFields.AuthWebhookMethods): UpdatableProjectFields; - hasAuthWebhookMethods(): boolean; - clearAuthWebhookMethods(): UpdatableProjectFields; - - getClientDeactivateThreshold(): google_protobuf_wrappers_pb.StringValue | undefined; - setClientDeactivateThreshold(value?: google_protobuf_wrappers_pb.StringValue): UpdatableProjectFields; - hasClientDeactivateThreshold(): boolean; - clearClientDeactivateThreshold(): UpdatableProjectFields; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): UpdatableProjectFields.AsObject; - static toObject(includeInstance: boolean, msg: UpdatableProjectFields): UpdatableProjectFields.AsObject; - static serializeBinaryToWriter(message: UpdatableProjectFields, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): UpdatableProjectFields; - static deserializeBinaryFromReader(message: UpdatableProjectFields, reader: jspb.BinaryReader): UpdatableProjectFields; -} +/** + * @generated from message yorkie.v1.TextNodeID + */ +export declare class TextNodeID extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 1; + */ + createdAt?: TimeTicket; -export namespace UpdatableProjectFields { - export type AsObject = { - name?: google_protobuf_wrappers_pb.StringValue.AsObject, - authWebhookUrl?: google_protobuf_wrappers_pb.StringValue.AsObject, - authWebhookMethods?: UpdatableProjectFields.AuthWebhookMethods.AsObject, - clientDeactivateThreshold?: google_protobuf_wrappers_pb.StringValue.AsObject, - } - - export class AuthWebhookMethods extends jspb.Message { - getMethodsList(): Array; - setMethodsList(value: Array): AuthWebhookMethods; - clearMethodsList(): AuthWebhookMethods; - addMethods(value: string, index?: number): AuthWebhookMethods; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): AuthWebhookMethods.AsObject; - static toObject(includeInstance: boolean, msg: AuthWebhookMethods): AuthWebhookMethods.AsObject; - static serializeBinaryToWriter(message: AuthWebhookMethods, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): AuthWebhookMethods; - static deserializeBinaryFromReader(message: AuthWebhookMethods, reader: jspb.BinaryReader): AuthWebhookMethods; - } - - export namespace AuthWebhookMethods { - export type AsObject = { - methodsList: Array, - } - } + /** + * @generated from field: int32 offset = 2; + */ + offset: number; -} + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TextNodeID"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): TextNodeID; -export class DocumentSummary extends jspb.Message { - getId(): string; - setId(value: string): DocumentSummary; - - getKey(): string; - setKey(value: string): DocumentSummary; - - getSnapshot(): string; - setSnapshot(value: string): DocumentSummary; - - getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined; - setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): DocumentSummary; - hasCreatedAt(): boolean; - clearCreatedAt(): DocumentSummary; - - getAccessedAt(): google_protobuf_timestamp_pb.Timestamp | undefined; - setAccessedAt(value?: google_protobuf_timestamp_pb.Timestamp): DocumentSummary; - hasAccessedAt(): boolean; - clearAccessedAt(): DocumentSummary; - - getUpdatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined; - setUpdatedAt(value?: google_protobuf_timestamp_pb.Timestamp): DocumentSummary; - hasUpdatedAt(): boolean; - clearUpdatedAt(): DocumentSummary; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DocumentSummary.AsObject; - static toObject(includeInstance: boolean, msg: DocumentSummary): DocumentSummary.AsObject; - static serializeBinaryToWriter(message: DocumentSummary, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DocumentSummary; - static deserializeBinaryFromReader(message: DocumentSummary, reader: jspb.BinaryReader): DocumentSummary; + static fromJson(jsonValue: JsonValue, options?: Partial): TextNodeID; + + static fromJsonString(jsonString: string, options?: Partial): TextNodeID; + + static equals(a: TextNodeID | PlainMessage | undefined, b: TextNodeID | PlainMessage | undefined): boolean; } -export namespace DocumentSummary { - export type AsObject = { - id: string, - key: string, - snapshot: string, - createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject, - accessedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject, - updatedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject, - } +/** + * @generated from message yorkie.v1.TreeNode + */ +export declare class TreeNode extends Message { + /** + * @generated from field: yorkie.v1.TreeNodeID id = 1; + */ + id?: TreeNodeID; + + /** + * @generated from field: string type = 2; + */ + type: string; + + /** + * @generated from field: string value = 3; + */ + value: string; + + /** + * @generated from field: yorkie.v1.TimeTicket removed_at = 4; + */ + removedAt?: TimeTicket; + + /** + * @generated from field: yorkie.v1.TreeNodeID ins_prev_id = 5; + */ + insPrevId?: TreeNodeID; + + /** + * @generated from field: yorkie.v1.TreeNodeID ins_next_id = 6; + */ + insNextId?: TreeNodeID; + + /** + * @generated from field: int32 depth = 7; + */ + depth: number; + + /** + * @generated from field: map attributes = 8; + */ + attributes: { [key: string]: NodeAttr }; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TreeNode"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): TreeNode; + + static fromJson(jsonValue: JsonValue, options?: Partial): TreeNode; + + static fromJsonString(jsonString: string, options?: Partial): TreeNode; + + static equals(a: TreeNode | PlainMessage | undefined, b: TreeNode | PlainMessage | undefined): boolean; } -export class PresenceChange extends jspb.Message { - getType(): PresenceChange.ChangeType; - setType(value: PresenceChange.ChangeType): PresenceChange; - - getPresence(): Presence | undefined; - setPresence(value?: Presence): PresenceChange; - hasPresence(): boolean; - clearPresence(): PresenceChange; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): PresenceChange.AsObject; - static toObject(includeInstance: boolean, msg: PresenceChange): PresenceChange.AsObject; - static serializeBinaryToWriter(message: PresenceChange, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): PresenceChange; - static deserializeBinaryFromReader(message: PresenceChange, reader: jspb.BinaryReader): PresenceChange; +/** + * @generated from message yorkie.v1.TreeNodes + */ +export declare class TreeNodes extends Message { + /** + * @generated from field: repeated yorkie.v1.TreeNode content = 1; + */ + content: TreeNode[]; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TreeNodes"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): TreeNodes; + + static fromJson(jsonValue: JsonValue, options?: Partial): TreeNodes; + + static fromJsonString(jsonString: string, options?: Partial): TreeNodes; + + static equals(a: TreeNodes | PlainMessage | undefined, b: TreeNodes | PlainMessage | undefined): boolean; } -export namespace PresenceChange { - export type AsObject = { - type: PresenceChange.ChangeType, - presence?: Presence.AsObject, - } - - export enum ChangeType { - CHANGE_TYPE_UNSPECIFIED = 0, - CHANGE_TYPE_PUT = 1, - CHANGE_TYPE_DELETE = 2, - CHANGE_TYPE_CLEAR = 3, - } +/** + * @generated from message yorkie.v1.TreeNodeID + */ +export declare class TreeNodeID extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 1; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: int32 offset = 2; + */ + offset: number; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TreeNodeID"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): TreeNodeID; + + static fromJson(jsonValue: JsonValue, options?: Partial): TreeNodeID; + + static fromJsonString(jsonString: string, options?: Partial): TreeNodeID; + + static equals(a: TreeNodeID | PlainMessage | undefined, b: TreeNodeID | PlainMessage | undefined): boolean; } -export class Presence extends jspb.Message { - getDataMap(): jspb.Map; - clearDataMap(): Presence; +/** + * @generated from message yorkie.v1.TreePos + */ +export declare class TreePos extends Message { + /** + * @generated from field: yorkie.v1.TreeNodeID parent_id = 1; + */ + parentId?: TreeNodeID; + + /** + * @generated from field: yorkie.v1.TreeNodeID left_sibling_id = 2; + */ + leftSiblingId?: TreeNodeID; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Presence.AsObject; - static toObject(includeInstance: boolean, msg: Presence): Presence.AsObject; - static serializeBinaryToWriter(message: Presence, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Presence; - static deserializeBinaryFromReader(message: Presence, reader: jspb.BinaryReader): Presence; + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TreePos"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): TreePos; + + static fromJson(jsonValue: JsonValue, options?: Partial): TreePos; + + static fromJsonString(jsonString: string, options?: Partial): TreePos; + + static equals(a: TreePos | PlainMessage | undefined, b: TreePos | PlainMessage | undefined): boolean; } -export namespace Presence { - export type AsObject = { - dataMap: Array<[string, string]>, - } +/** + * @generated from message yorkie.v1.User + */ +export declare class User extends Message { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string username = 2; + */ + username: string; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 3; + */ + createdAt?: Timestamp; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.User"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): User; + + static fromJson(jsonValue: JsonValue, options?: Partial): User; + + static fromJsonString(jsonString: string, options?: Partial): User; + + static equals(a: User | PlainMessage | undefined, b: User | PlainMessage | undefined): boolean; } -export class Checkpoint extends jspb.Message { - getServerSeq(): string; - setServerSeq(value: string): Checkpoint; +/** + * @generated from message yorkie.v1.Project + */ +export declare class Project extends Message { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string name = 2; + */ + name: string; + + /** + * @generated from field: string public_key = 3; + */ + publicKey: string; + + /** + * @generated from field: string secret_key = 4; + */ + secretKey: string; + + /** + * @generated from field: string auth_webhook_url = 5; + */ + authWebhookUrl: string; + + /** + * @generated from field: repeated string auth_webhook_methods = 6; + */ + authWebhookMethods: string[]; + + /** + * @generated from field: string client_deactivate_threshold = 7; + */ + clientDeactivateThreshold: string; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 8; + */ + createdAt?: Timestamp; + + /** + * @generated from field: google.protobuf.Timestamp updated_at = 9; + */ + updatedAt?: Timestamp; - getClientSeq(): number; - setClientSeq(value: number): Checkpoint; + constructor(data?: PartialMessage); - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Checkpoint.AsObject; - static toObject(includeInstance: boolean, msg: Checkpoint): Checkpoint.AsObject; - static serializeBinaryToWriter(message: Checkpoint, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Checkpoint; - static deserializeBinaryFromReader(message: Checkpoint, reader: jspb.BinaryReader): Checkpoint; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Project"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Project; + + static fromJson(jsonValue: JsonValue, options?: Partial): Project; + + static fromJsonString(jsonString: string, options?: Partial): Project; + + static equals(a: Project | PlainMessage | undefined, b: Project | PlainMessage | undefined): boolean; } -export namespace Checkpoint { - export type AsObject = { - serverSeq: string, - clientSeq: number, - } +/** + * @generated from message yorkie.v1.UpdatableProjectFields + */ +export declare class UpdatableProjectFields extends Message { + /** + * @generated from field: google.protobuf.StringValue name = 1; + */ + name?: string; + + /** + * @generated from field: google.protobuf.StringValue auth_webhook_url = 2; + */ + authWebhookUrl?: string; + + /** + * @generated from field: yorkie.v1.UpdatableProjectFields.AuthWebhookMethods auth_webhook_methods = 3; + */ + authWebhookMethods?: UpdatableProjectFields_AuthWebhookMethods; + + /** + * @generated from field: google.protobuf.StringValue client_deactivate_threshold = 4; + */ + clientDeactivateThreshold?: string; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.UpdatableProjectFields"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): UpdatableProjectFields; + + static fromJson(jsonValue: JsonValue, options?: Partial): UpdatableProjectFields; + + static fromJsonString(jsonString: string, options?: Partial): UpdatableProjectFields; + + static equals(a: UpdatableProjectFields | PlainMessage | undefined, b: UpdatableProjectFields | PlainMessage | undefined): boolean; } -export class TextNodePos extends jspb.Message { - getCreatedAt(): TimeTicket | undefined; - setCreatedAt(value?: TimeTicket): TextNodePos; - hasCreatedAt(): boolean; - clearCreatedAt(): TextNodePos; +/** + * @generated from message yorkie.v1.UpdatableProjectFields.AuthWebhookMethods + */ +export declare class UpdatableProjectFields_AuthWebhookMethods extends Message { + /** + * @generated from field: repeated string methods = 1; + */ + methods: string[]; + + constructor(data?: PartialMessage); - getOffset(): number; - setOffset(value: number): TextNodePos; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.UpdatableProjectFields.AuthWebhookMethods"; + static readonly fields: FieldList; - getRelativeOffset(): number; - setRelativeOffset(value: number): TextNodePos; + static fromBinary(bytes: Uint8Array, options?: Partial): UpdatableProjectFields_AuthWebhookMethods; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TextNodePos.AsObject; - static toObject(includeInstance: boolean, msg: TextNodePos): TextNodePos.AsObject; - static serializeBinaryToWriter(message: TextNodePos, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TextNodePos; - static deserializeBinaryFromReader(message: TextNodePos, reader: jspb.BinaryReader): TextNodePos; + static fromJson(jsonValue: JsonValue, options?: Partial): UpdatableProjectFields_AuthWebhookMethods; + + static fromJsonString(jsonString: string, options?: Partial): UpdatableProjectFields_AuthWebhookMethods; + + static equals(a: UpdatableProjectFields_AuthWebhookMethods | PlainMessage | undefined, b: UpdatableProjectFields_AuthWebhookMethods | PlainMessage | undefined): boolean; } -export namespace TextNodePos { - export type AsObject = { - createdAt?: TimeTicket.AsObject, - offset: number, - relativeOffset: number, - } +/** + * @generated from message yorkie.v1.DocumentSummary + */ +export declare class DocumentSummary extends Message { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string key = 2; + */ + key: string; + + /** + * @generated from field: string snapshot = 3; + */ + snapshot: string; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 4; + */ + createdAt?: Timestamp; + + /** + * @generated from field: google.protobuf.Timestamp accessed_at = 5; + */ + accessedAt?: Timestamp; + + /** + * @generated from field: google.protobuf.Timestamp updated_at = 6; + */ + updatedAt?: Timestamp; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DocumentSummary"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): DocumentSummary; + + static fromJson(jsonValue: JsonValue, options?: Partial): DocumentSummary; + + static fromJsonString(jsonString: string, options?: Partial): DocumentSummary; + + static equals(a: DocumentSummary | PlainMessage | undefined, b: DocumentSummary | PlainMessage | undefined): boolean; } -export class TimeTicket extends jspb.Message { - getLamport(): string; - setLamport(value: string): TimeTicket; +/** + * @generated from message yorkie.v1.PresenceChange + */ +export declare class PresenceChange extends Message { + /** + * @generated from field: yorkie.v1.PresenceChange.ChangeType type = 1; + */ + type: PresenceChange_ChangeType; - getDelimiter(): number; - setDelimiter(value: number): TimeTicket; + /** + * @generated from field: yorkie.v1.Presence presence = 2; + */ + presence?: Presence; - getActorId(): Uint8Array | string; - getActorId_asU8(): Uint8Array; - getActorId_asB64(): string; - setActorId(value: Uint8Array | string): TimeTicket; + constructor(data?: PartialMessage); - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): TimeTicket.AsObject; - static toObject(includeInstance: boolean, msg: TimeTicket): TimeTicket.AsObject; - static serializeBinaryToWriter(message: TimeTicket, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): TimeTicket; - static deserializeBinaryFromReader(message: TimeTicket, reader: jspb.BinaryReader): TimeTicket; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.PresenceChange"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): PresenceChange; + + static fromJson(jsonValue: JsonValue, options?: Partial): PresenceChange; + + static fromJsonString(jsonString: string, options?: Partial): PresenceChange; + + static equals(a: PresenceChange | PlainMessage | undefined, b: PresenceChange | PlainMessage | undefined): boolean; } -export namespace TimeTicket { - export type AsObject = { - lamport: string, - delimiter: number, - actorId: Uint8Array | string, - } +/** + * @generated from enum yorkie.v1.PresenceChange.ChangeType + */ +export declare enum PresenceChange_ChangeType { + /** + * @generated from enum value: CHANGE_TYPE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: CHANGE_TYPE_PUT = 1; + */ + PUT = 1, + + /** + * @generated from enum value: CHANGE_TYPE_DELETE = 2; + */ + DELETE = 2, + + /** + * @generated from enum value: CHANGE_TYPE_CLEAR = 3; + */ + CLEAR = 3, } -export class DocEventBody extends jspb.Message { - getTopic(): string; - setTopic(value: string): DocEventBody; - - getPayload(): Uint8Array | string; - getPayload_asU8(): Uint8Array; - getPayload_asB64(): string; - setPayload(value: Uint8Array | string): DocEventBody; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DocEventBody.AsObject; - static toObject(includeInstance: boolean, msg: DocEventBody): DocEventBody.AsObject; - static serializeBinaryToWriter(message: DocEventBody, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DocEventBody; - static deserializeBinaryFromReader(message: DocEventBody, reader: jspb.BinaryReader): DocEventBody; +/** + * @generated from message yorkie.v1.Presence + */ +export declare class Presence extends Message { + /** + * @generated from field: map data = 1; + */ + data: { [key: string]: string }; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Presence"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Presence; + + static fromJson(jsonValue: JsonValue, options?: Partial): Presence; + + static fromJsonString(jsonString: string, options?: Partial): Presence; + + static equals(a: Presence | PlainMessage | undefined, b: Presence | PlainMessage | undefined): boolean; } -export namespace DocEventBody { - export type AsObject = { - topic: string, - payload: Uint8Array | string, - } +/** + * @generated from message yorkie.v1.Checkpoint + */ +export declare class Checkpoint extends Message { + /** + * @generated from field: int64 server_seq = 1 [jstype = JS_STRING]; + */ + serverSeq: string; + + /** + * @generated from field: uint32 client_seq = 2; + */ + clientSeq: number; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.Checkpoint"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): Checkpoint; + + static fromJson(jsonValue: JsonValue, options?: Partial): Checkpoint; + + static fromJsonString(jsonString: string, options?: Partial): Checkpoint; + + static equals(a: Checkpoint | PlainMessage | undefined, b: Checkpoint | PlainMessage | undefined): boolean; } -export class DocEvent extends jspb.Message { - getType(): DocEventType; - setType(value: DocEventType): DocEvent; +/** + * @generated from message yorkie.v1.TextNodePos + */ +export declare class TextNodePos extends Message { + /** + * @generated from field: yorkie.v1.TimeTicket created_at = 1; + */ + createdAt?: TimeTicket; + + /** + * @generated from field: int32 offset = 2; + */ + offset: number; + + /** + * @generated from field: int32 relative_offset = 3; + */ + relativeOffset: number; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TextNodePos"; + static readonly fields: FieldList; - getPublisher(): string; - setPublisher(value: string): DocEvent; + static fromBinary(bytes: Uint8Array, options?: Partial): TextNodePos; - getBody(): DocEventBody | undefined; - setBody(value?: DocEventBody): DocEvent; - hasBody(): boolean; - clearBody(): DocEvent; + static fromJson(jsonValue: JsonValue, options?: Partial): TextNodePos; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DocEvent.AsObject; - static toObject(includeInstance: boolean, msg: DocEvent): DocEvent.AsObject; - static serializeBinaryToWriter(message: DocEvent, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DocEvent; - static deserializeBinaryFromReader(message: DocEvent, reader: jspb.BinaryReader): DocEvent; + static fromJsonString(jsonString: string, options?: Partial): TextNodePos; + + static equals(a: TextNodePos | PlainMessage | undefined, b: TextNodePos | PlainMessage | undefined): boolean; } -export namespace DocEvent { - export type AsObject = { - type: DocEventType, - publisher: string, - body?: DocEventBody.AsObject, - } +/** + * @generated from message yorkie.v1.TimeTicket + */ +export declare class TimeTicket extends Message { + /** + * @generated from field: int64 lamport = 1 [jstype = JS_STRING]; + */ + lamport: string; + + /** + * @generated from field: uint32 delimiter = 2; + */ + delimiter: number; + + /** + * @generated from field: bytes actor_id = 3; + */ + actorId: Uint8Array; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.TimeTicket"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): TimeTicket; + + static fromJson(jsonValue: JsonValue, options?: Partial): TimeTicket; + + static fromJsonString(jsonString: string, options?: Partial): TimeTicket; + + static equals(a: TimeTicket | PlainMessage | undefined, b: TimeTicket | PlainMessage | undefined): boolean; } -export enum ValueType { - VALUE_TYPE_NULL = 0, - VALUE_TYPE_BOOLEAN = 1, - VALUE_TYPE_INTEGER = 2, - VALUE_TYPE_LONG = 3, - VALUE_TYPE_DOUBLE = 4, - VALUE_TYPE_STRING = 5, - VALUE_TYPE_BYTES = 6, - VALUE_TYPE_DATE = 7, - VALUE_TYPE_JSON_OBJECT = 8, - VALUE_TYPE_JSON_ARRAY = 9, - VALUE_TYPE_TEXT = 10, - VALUE_TYPE_INTEGER_CNT = 11, - VALUE_TYPE_LONG_CNT = 12, - VALUE_TYPE_TREE = 13, +/** + * @generated from message yorkie.v1.DocEventBody + */ +export declare class DocEventBody extends Message { + /** + * @generated from field: string topic = 1; + */ + topic: string; + + /** + * @generated from field: bytes payload = 2; + */ + payload: Uint8Array; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DocEventBody"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): DocEventBody; + + static fromJson(jsonValue: JsonValue, options?: Partial): DocEventBody; + + static fromJsonString(jsonString: string, options?: Partial): DocEventBody; + + static equals(a: DocEventBody | PlainMessage | undefined, b: DocEventBody | PlainMessage | undefined): boolean; } -export enum DocEventType { - DOC_EVENT_TYPE_DOCUMENT_CHANGED = 0, - DOC_EVENT_TYPE_DOCUMENT_WATCHED = 1, - DOC_EVENT_TYPE_DOCUMENT_UNWATCHED = 2, - DOC_EVENT_TYPE_DOCUMENT_BROADCAST = 3, + +/** + * @generated from message yorkie.v1.DocEvent + */ +export declare class DocEvent extends Message { + /** + * @generated from field: yorkie.v1.DocEventType type = 1; + */ + type: DocEventType; + + /** + * @generated from field: string publisher = 2; + */ + publisher: string; + + /** + * @generated from field: yorkie.v1.DocEventBody body = 3; + */ + body?: DocEventBody; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DocEvent"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): DocEvent; + + static fromJson(jsonValue: JsonValue, options?: Partial): DocEvent; + + static fromJsonString(jsonString: string, options?: Partial): DocEvent; + + static equals(a: DocEvent | PlainMessage | undefined, b: DocEvent | PlainMessage | undefined): boolean; } + diff --git a/src/api/yorkie/v1/resources_pb.js b/src/api/yorkie/v1/resources_pb.js index f97ef6105..dd58b9bc0 100644 --- a/src/api/yorkie/v1/resources_pb.js +++ b/src/api/yorkie/v1/resources_pb.js @@ -1,13502 +1,722 @@ -// source: yorkie/v1/resources.proto -/** - * @fileoverview - * @enhanceable - * @suppress {missingRequire} reports error on implicit type usages. - * @suppress {messageConventions} JS Compiler reports an error if a variable or - * field starts with 'MSG_' and isn't a translatable message. - * @public - */ -// GENERATED CODE -- DO NOT EDIT! +// +// Copyright 2022 The Yorkie Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v1.6.0 with parameter "target=js+dts,js_import_style=legacy_commonjs" +// @generated from file src/api/yorkie/v1/resources.proto (package yorkie.v1, syntax proto3) /* eslint-disable */ // @ts-nocheck -var jspb = require('google-protobuf'); -var goog = jspb; -var global = - (typeof globalThis !== 'undefined' && globalThis) || - (typeof window !== 'undefined' && window) || - (typeof global !== 'undefined' && global) || - (typeof self !== 'undefined' && self) || - (function () { return this; }).call(null) || - Function('return this')(); - -var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js'); -goog.object.extend(proto, google_protobuf_timestamp_pb); -var google_protobuf_wrappers_pb = require('google-protobuf/google/protobuf/wrappers_pb.js'); -goog.object.extend(proto, google_protobuf_wrappers_pb); -goog.exportSymbol('proto.yorkie.v1.Change', null, global); -goog.exportSymbol('proto.yorkie.v1.ChangeID', null, global); -goog.exportSymbol('proto.yorkie.v1.ChangePack', null, global); -goog.exportSymbol('proto.yorkie.v1.Checkpoint', null, global); -goog.exportSymbol('proto.yorkie.v1.DocEvent', null, global); -goog.exportSymbol('proto.yorkie.v1.DocEventBody', null, global); -goog.exportSymbol('proto.yorkie.v1.DocEventType', null, global); -goog.exportSymbol('proto.yorkie.v1.DocumentSummary', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.BodyCase', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.Counter', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.JSONArray', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.JSONObject', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.Primitive', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.Text', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElement.Tree', null, global); -goog.exportSymbol('proto.yorkie.v1.JSONElementSimple', null, global); -goog.exportSymbol('proto.yorkie.v1.NodeAttr', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Add', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.BodyCase', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Edit', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Increase', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Move', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Remove', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Select', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Set', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.Style', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.TreeEdit', null, global); -goog.exportSymbol('proto.yorkie.v1.Operation.TreeStyle', null, global); -goog.exportSymbol('proto.yorkie.v1.Presence', null, global); -goog.exportSymbol('proto.yorkie.v1.PresenceChange', null, global); -goog.exportSymbol('proto.yorkie.v1.PresenceChange.ChangeType', null, global); -goog.exportSymbol('proto.yorkie.v1.Project', null, global); -goog.exportSymbol('proto.yorkie.v1.RGANode', null, global); -goog.exportSymbol('proto.yorkie.v1.RHTNode', null, global); -goog.exportSymbol('proto.yorkie.v1.Snapshot', null, global); -goog.exportSymbol('proto.yorkie.v1.TextNode', null, global); -goog.exportSymbol('proto.yorkie.v1.TextNodeID', null, global); -goog.exportSymbol('proto.yorkie.v1.TextNodePos', null, global); -goog.exportSymbol('proto.yorkie.v1.TimeTicket', null, global); -goog.exportSymbol('proto.yorkie.v1.TreeNode', null, global); -goog.exportSymbol('proto.yorkie.v1.TreeNodeID', null, global); -goog.exportSymbol('proto.yorkie.v1.TreeNodes', null, global); -goog.exportSymbol('proto.yorkie.v1.TreePos', null, global); -goog.exportSymbol('proto.yorkie.v1.UpdatableProjectFields', null, global); -goog.exportSymbol('proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods', null, global); -goog.exportSymbol('proto.yorkie.v1.User', null, global); -goog.exportSymbol('proto.yorkie.v1.ValueType', null, global); -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Snapshot = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Snapshot, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Snapshot.displayName = 'proto.yorkie.v1.Snapshot'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.ChangePack = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.ChangePack.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.ChangePack, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.ChangePack.displayName = 'proto.yorkie.v1.ChangePack'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Change = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.Change.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.Change, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Change.displayName = 'proto.yorkie.v1.Change'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.ChangeID = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.ChangeID, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.ChangeID.displayName = 'proto.yorkie.v1.ChangeID'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, proto.yorkie.v1.Operation.oneofGroups_); -}; -goog.inherits(proto.yorkie.v1.Operation, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.displayName = 'proto.yorkie.v1.Operation'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Set = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Set, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Set.displayName = 'proto.yorkie.v1.Operation.Set'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Add = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Add, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Add.displayName = 'proto.yorkie.v1.Operation.Add'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Move = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Move, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Move.displayName = 'proto.yorkie.v1.Operation.Move'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Remove = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Remove, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Remove.displayName = 'proto.yorkie.v1.Operation.Remove'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Edit = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Edit, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Edit.displayName = 'proto.yorkie.v1.Operation.Edit'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Select = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Select, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Select.displayName = 'proto.yorkie.v1.Operation.Select'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Style = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Style, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Style.displayName = 'proto.yorkie.v1.Operation.Style'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.Increase = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.Increase, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.Increase.displayName = 'proto.yorkie.v1.Operation.Increase'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.TreeEdit = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.Operation.TreeEdit.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.Operation.TreeEdit, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.TreeEdit.displayName = 'proto.yorkie.v1.Operation.TreeEdit'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Operation.TreeStyle = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Operation.TreeStyle, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Operation.TreeStyle.displayName = 'proto.yorkie.v1.Operation.TreeStyle'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElementSimple = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.JSONElementSimple, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElementSimple.displayName = 'proto.yorkie.v1.JSONElementSimple'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, proto.yorkie.v1.JSONElement.oneofGroups_); -}; -goog.inherits(proto.yorkie.v1.JSONElement, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.displayName = 'proto.yorkie.v1.JSONElement'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement.JSONObject = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.JSONElement.JSONObject.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.JSONElement.JSONObject, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.JSONObject.displayName = 'proto.yorkie.v1.JSONElement.JSONObject'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement.JSONArray = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.JSONElement.JSONArray.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.JSONElement.JSONArray, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.JSONArray.displayName = 'proto.yorkie.v1.JSONElement.JSONArray'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement.Primitive = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.JSONElement.Primitive, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.Primitive.displayName = 'proto.yorkie.v1.JSONElement.Primitive'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement.Text = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.JSONElement.Text.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.JSONElement.Text, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.Text.displayName = 'proto.yorkie.v1.JSONElement.Text'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement.Counter = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.JSONElement.Counter, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.Counter.displayName = 'proto.yorkie.v1.JSONElement.Counter'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.JSONElement.Tree = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.JSONElement.Tree.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.JSONElement.Tree, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.JSONElement.Tree.displayName = 'proto.yorkie.v1.JSONElement.Tree'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.RHTNode = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.RHTNode, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.RHTNode.displayName = 'proto.yorkie.v1.RHTNode'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.RGANode = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.RGANode, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.RGANode.displayName = 'proto.yorkie.v1.RGANode'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.NodeAttr = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.NodeAttr, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.NodeAttr.displayName = 'proto.yorkie.v1.NodeAttr'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TextNode = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TextNode, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TextNode.displayName = 'proto.yorkie.v1.TextNode'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TextNodeID = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TextNodeID, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TextNodeID.displayName = 'proto.yorkie.v1.TextNodeID'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TreeNode = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TreeNode, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TreeNode.displayName = 'proto.yorkie.v1.TreeNode'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TreeNodes = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.TreeNodes.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.TreeNodes, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TreeNodes.displayName = 'proto.yorkie.v1.TreeNodes'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TreeNodeID = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TreeNodeID, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TreeNodeID.displayName = 'proto.yorkie.v1.TreeNodeID'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TreePos = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TreePos, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TreePos.displayName = 'proto.yorkie.v1.TreePos'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.User = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.User, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.User.displayName = 'proto.yorkie.v1.User'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Project = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.Project.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.Project, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Project.displayName = 'proto.yorkie.v1.Project'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.UpdatableProjectFields = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.UpdatableProjectFields, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.UpdatableProjectFields.displayName = 'proto.yorkie.v1.UpdatableProjectFields'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.displayName = 'proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DocumentSummary = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DocumentSummary, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DocumentSummary.displayName = 'proto.yorkie.v1.DocumentSummary'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.PresenceChange = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.PresenceChange, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.PresenceChange.displayName = 'proto.yorkie.v1.PresenceChange'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Presence = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Presence, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Presence.displayName = 'proto.yorkie.v1.Presence'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.Checkpoint = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.Checkpoint, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.Checkpoint.displayName = 'proto.yorkie.v1.Checkpoint'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TextNodePos = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TextNodePos, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TextNodePos.displayName = 'proto.yorkie.v1.TextNodePos'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.TimeTicket = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.TimeTicket, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.TimeTicket.displayName = 'proto.yorkie.v1.TimeTicket'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DocEventBody = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DocEventBody, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DocEventBody.displayName = 'proto.yorkie.v1.DocEventBody'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DocEvent = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DocEvent, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DocEvent.displayName = 'proto.yorkie.v1.DocEvent'; -} - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Snapshot.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Snapshot.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Snapshot} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Snapshot.toObject = function(includeInstance, msg) { - var f, obj = { - root: (f = msg.getRoot()) && proto.yorkie.v1.JSONElement.toObject(includeInstance, f), - presencesMap: (f = msg.getPresencesMap()) ? f.toObject(includeInstance, proto.yorkie.v1.Presence.toObject) : [] - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Snapshot} - */ -proto.yorkie.v1.Snapshot.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Snapshot; - return proto.yorkie.v1.Snapshot.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Snapshot} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Snapshot} - */ -proto.yorkie.v1.Snapshot.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.JSONElement; - reader.readMessage(value,proto.yorkie.v1.JSONElement.deserializeBinaryFromReader); - msg.setRoot(value); - break; - case 2: - var value = msg.getPresencesMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.Presence.deserializeBinaryFromReader, "", new proto.yorkie.v1.Presence()); - }); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Snapshot.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Snapshot.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Snapshot} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Snapshot.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getRoot(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.JSONElement.serializeBinaryToWriter - ); - } - f = message.getPresencesMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(2, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.Presence.serializeBinaryToWriter); - } -}; - - -/** - * optional JSONElement root = 1; - * @return {?proto.yorkie.v1.JSONElement} - */ -proto.yorkie.v1.Snapshot.prototype.getRoot = function() { - return /** @type{?proto.yorkie.v1.JSONElement} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement|undefined} value - * @return {!proto.yorkie.v1.Snapshot} returns this -*/ -proto.yorkie.v1.Snapshot.prototype.setRoot = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Snapshot} returns this - */ -proto.yorkie.v1.Snapshot.prototype.clearRoot = function() { - return this.setRoot(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Snapshot.prototype.hasRoot = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * map presences = 2; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Snapshot.prototype.getPresencesMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 2, opt_noLazyCreate, - proto.yorkie.v1.Presence)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Snapshot} returns this - */ -proto.yorkie.v1.Snapshot.prototype.clearPresencesMap = function() { - this.getPresencesMap().clear(); - return this; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.ChangePack.repeatedFields_ = [4]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.ChangePack.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.ChangePack.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.ChangePack} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ChangePack.toObject = function(includeInstance, msg) { - var f, obj = { - documentKey: jspb.Message.getFieldWithDefault(msg, 1, ""), - checkpoint: (f = msg.getCheckpoint()) && proto.yorkie.v1.Checkpoint.toObject(includeInstance, f), - snapshot: msg.getSnapshot_asB64(), - changesList: jspb.Message.toObjectList(msg.getChangesList(), - proto.yorkie.v1.Change.toObject, includeInstance), - minSyncedTicket: (f = msg.getMinSyncedTicket()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - isRemoved: jspb.Message.getBooleanFieldWithDefault(msg, 6, false) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.ChangePack.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.ChangePack; - return proto.yorkie.v1.ChangePack.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.ChangePack} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.ChangePack.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentKey(value); - break; - case 2: - var value = new proto.yorkie.v1.Checkpoint; - reader.readMessage(value,proto.yorkie.v1.Checkpoint.deserializeBinaryFromReader); - msg.setCheckpoint(value); - break; - case 3: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setSnapshot(value); - break; - case 4: - var value = new proto.yorkie.v1.Change; - reader.readMessage(value,proto.yorkie.v1.Change.deserializeBinaryFromReader); - msg.addChanges(value); - break; - case 5: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMinSyncedTicket(value); - break; - case 6: - var value = /** @type {boolean} */ (reader.readBool()); - msg.setIsRemoved(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.ChangePack.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.ChangePack.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.ChangePack} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ChangePack.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getDocumentKey(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getCheckpoint(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.Checkpoint.serializeBinaryToWriter - ); - } - f = message.getSnapshot_asU8(); - if (f.length > 0) { - writer.writeBytes( - 3, - f - ); - } - f = message.getChangesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 4, - f, - proto.yorkie.v1.Change.serializeBinaryToWriter - ); - } - f = message.getMinSyncedTicket(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getIsRemoved(); - if (f) { - writer.writeBool( - 6, - f - ); - } -}; - - -/** - * optional string document_key = 1; - * @return {string} - */ -proto.yorkie.v1.ChangePack.prototype.getDocumentKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.ChangePack} returns this - */ -proto.yorkie.v1.ChangePack.prototype.setDocumentKey = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional Checkpoint checkpoint = 2; - * @return {?proto.yorkie.v1.Checkpoint} - */ -proto.yorkie.v1.ChangePack.prototype.getCheckpoint = function() { - return /** @type{?proto.yorkie.v1.Checkpoint} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Checkpoint, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.Checkpoint|undefined} value - * @return {!proto.yorkie.v1.ChangePack} returns this -*/ -proto.yorkie.v1.ChangePack.prototype.setCheckpoint = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.ChangePack} returns this - */ -proto.yorkie.v1.ChangePack.prototype.clearCheckpoint = function() { - return this.setCheckpoint(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.ChangePack.prototype.hasCheckpoint = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional bytes snapshot = 3; - * @return {string} - */ -proto.yorkie.v1.ChangePack.prototype.getSnapshot = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * optional bytes snapshot = 3; - * This is a type-conversion wrapper around `getSnapshot()` - * @return {string} - */ -proto.yorkie.v1.ChangePack.prototype.getSnapshot_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getSnapshot())); -}; - - -/** - * optional bytes snapshot = 3; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getSnapshot()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.ChangePack.prototype.getSnapshot_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getSnapshot())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.ChangePack} returns this - */ -proto.yorkie.v1.ChangePack.prototype.setSnapshot = function(value) { - return jspb.Message.setProto3BytesField(this, 3, value); -}; - - -/** - * repeated Change changes = 4; - * @return {!Array} - */ -proto.yorkie.v1.ChangePack.prototype.getChangesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.Change, 4)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.ChangePack} returns this -*/ -proto.yorkie.v1.ChangePack.prototype.setChangesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 4, value); -}; - - -/** - * @param {!proto.yorkie.v1.Change=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.Change} - */ -proto.yorkie.v1.ChangePack.prototype.addChanges = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 4, opt_value, proto.yorkie.v1.Change, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.ChangePack} returns this +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); + +const { proto3, StringValue, Timestamp } = require("@bufbuild/protobuf"); + +/** + * @generated from enum yorkie.v1.ValueType + */ +const ValueType = proto3.makeEnum( + "yorkie.v1.ValueType", + [ + {no: 0, name: "VALUE_TYPE_NULL", localName: "NULL"}, + {no: 1, name: "VALUE_TYPE_BOOLEAN", localName: "BOOLEAN"}, + {no: 2, name: "VALUE_TYPE_INTEGER", localName: "INTEGER"}, + {no: 3, name: "VALUE_TYPE_LONG", localName: "LONG"}, + {no: 4, name: "VALUE_TYPE_DOUBLE", localName: "DOUBLE"}, + {no: 5, name: "VALUE_TYPE_STRING", localName: "STRING"}, + {no: 6, name: "VALUE_TYPE_BYTES", localName: "BYTES"}, + {no: 7, name: "VALUE_TYPE_DATE", localName: "DATE"}, + {no: 8, name: "VALUE_TYPE_JSON_OBJECT", localName: "JSON_OBJECT"}, + {no: 9, name: "VALUE_TYPE_JSON_ARRAY", localName: "JSON_ARRAY"}, + {no: 10, name: "VALUE_TYPE_TEXT", localName: "TEXT"}, + {no: 11, name: "VALUE_TYPE_INTEGER_CNT", localName: "INTEGER_CNT"}, + {no: 12, name: "VALUE_TYPE_LONG_CNT", localName: "LONG_CNT"}, + {no: 13, name: "VALUE_TYPE_TREE", localName: "TREE"}, + ], +); + +/** + * @generated from enum yorkie.v1.DocEventType + */ +const DocEventType = proto3.makeEnum( + "yorkie.v1.DocEventType", + [ + {no: 0, name: "DOC_EVENT_TYPE_DOCUMENT_CHANGED", localName: "DOCUMENT_CHANGED"}, + {no: 1, name: "DOC_EVENT_TYPE_DOCUMENT_WATCHED", localName: "DOCUMENT_WATCHED"}, + {no: 2, name: "DOC_EVENT_TYPE_DOCUMENT_UNWATCHED", localName: "DOCUMENT_UNWATCHED"}, + {no: 3, name: "DOC_EVENT_TYPE_DOCUMENT_BROADCAST", localName: "DOCUMENT_BROADCAST"}, + ], +); + +/** + * /////////////////////////////////////// + * Messages for Snapshot // + * /////////////////////////////////////// + * + * @generated from message yorkie.v1.Snapshot + */ +const Snapshot = proto3.makeMessageType( + "yorkie.v1.Snapshot", + () => [ + { no: 1, name: "root", kind: "message", T: JSONElement }, + { no: 2, name: "presences", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: Presence} }, + ], +); + +/** + * ChangePack is a message that contains all changes that occurred in a document. + * It is used to synchronize changes between clients and servers. + * + * @generated from message yorkie.v1.ChangePack + */ +const ChangePack = proto3.makeMessageType( + "yorkie.v1.ChangePack", + () => [ + { no: 1, name: "document_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "checkpoint", kind: "message", T: Checkpoint }, + { no: 3, name: "snapshot", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + { no: 4, name: "changes", kind: "message", T: Change, repeated: true }, + { no: 5, name: "min_synced_ticket", kind: "message", T: TimeTicket }, + { no: 6, name: "is_removed", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + ], +); + +/** + * @generated from message yorkie.v1.Change + */ +const Change = proto3.makeMessageType( + "yorkie.v1.Change", + () => [ + { no: 1, name: "id", kind: "message", T: ChangeID }, + { no: 2, name: "message", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "operations", kind: "message", T: Operation, repeated: true }, + { no: 4, name: "presence_change", kind: "message", T: PresenceChange }, + ], +); + +/** + * @generated from message yorkie.v1.ChangeID + */ +const ChangeID = proto3.makeMessageType( + "yorkie.v1.ChangeID", + () => [ + { no: 1, name: "client_seq", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + { no: 2, name: "server_seq", kind: "scalar", T: 3 /* ScalarType.INT64 */, L: 1 /* LongType.STRING */ }, + { no: 3, name: "lamport", kind: "scalar", T: 3 /* ScalarType.INT64 */, L: 1 /* LongType.STRING */ }, + { no: 4, name: "actor_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + ], +); + +/** + * @generated from message yorkie.v1.Operation + */ +const Operation = proto3.makeMessageType( + "yorkie.v1.Operation", + () => [ + { no: 1, name: "set", kind: "message", T: Operation_Set, oneof: "body" }, + { no: 2, name: "add", kind: "message", T: Operation_Add, oneof: "body" }, + { no: 3, name: "move", kind: "message", T: Operation_Move, oneof: "body" }, + { no: 4, name: "remove", kind: "message", T: Operation_Remove, oneof: "body" }, + { no: 5, name: "edit", kind: "message", T: Operation_Edit, oneof: "body" }, + { no: 6, name: "select", kind: "message", T: Operation_Select, oneof: "body" }, + { no: 7, name: "style", kind: "message", T: Operation_Style, oneof: "body" }, + { no: 8, name: "increase", kind: "message", T: Operation_Increase, oneof: "body" }, + { no: 9, name: "tree_edit", kind: "message", T: Operation_TreeEdit, oneof: "body" }, + { no: 10, name: "tree_style", kind: "message", T: Operation_TreeStyle, oneof: "body" }, + ], +); + +/** + * @generated from message yorkie.v1.Operation.Set + */ +const Operation_Set = proto3.makeMessageType( + "yorkie.v1.Operation.Set", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "value", kind: "message", T: JSONElementSimple }, + { no: 4, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_Set"}, +); + +/** + * @generated from message yorkie.v1.Operation.Add + */ +const Operation_Add = proto3.makeMessageType( + "yorkie.v1.Operation.Add", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "prev_created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "value", kind: "message", T: JSONElementSimple }, + { no: 4, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_Add"}, +); + +/** + * @generated from message yorkie.v1.Operation.Move + */ +const Operation_Move = proto3.makeMessageType( + "yorkie.v1.Operation.Move", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "prev_created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "created_at", kind: "message", T: TimeTicket }, + { no: 4, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_Move"}, +); + +/** + * @generated from message yorkie.v1.Operation.Remove + */ +const Operation_Remove = proto3.makeMessageType( + "yorkie.v1.Operation.Remove", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_Remove"}, +); + +/** + * @generated from message yorkie.v1.Operation.Edit + */ +const Operation_Edit = proto3.makeMessageType( + "yorkie.v1.Operation.Edit", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "from", kind: "message", T: TextNodePos }, + { no: 3, name: "to", kind: "message", T: TextNodePos }, + { no: 4, name: "created_at_map_by_actor", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: TimeTicket} }, + { no: 5, name: "content", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 6, name: "executed_at", kind: "message", T: TimeTicket }, + { no: 7, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} }, + ], + {localName: "Operation_Edit"}, +); + +/** + * NOTE(hackerwins): Select Operation is not used in the current version. + * In the previous version, it was used to represent selection of Text. + * However, it has been replaced by Presence now. It is retained for backward + * compatibility purposes. + * + * @generated from message yorkie.v1.Operation.Select + */ +const Operation_Select = proto3.makeMessageType( + "yorkie.v1.Operation.Select", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "from", kind: "message", T: TextNodePos }, + { no: 3, name: "to", kind: "message", T: TextNodePos }, + { no: 4, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_Select"}, +); + +/** + * @generated from message yorkie.v1.Operation.Style + */ +const Operation_Style = proto3.makeMessageType( + "yorkie.v1.Operation.Style", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "from", kind: "message", T: TextNodePos }, + { no: 3, name: "to", kind: "message", T: TextNodePos }, + { no: 4, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} }, + { no: 5, name: "executed_at", kind: "message", T: TimeTicket }, + { no: 6, name: "created_at_map_by_actor", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: TimeTicket} }, + ], + {localName: "Operation_Style"}, +); + +/** + * @generated from message yorkie.v1.Operation.Increase + */ +const Operation_Increase = proto3.makeMessageType( + "yorkie.v1.Operation.Increase", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "value", kind: "message", T: JSONElementSimple }, + { no: 3, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_Increase"}, +); + +/** + * @generated from message yorkie.v1.Operation.TreeEdit + */ +const Operation_TreeEdit = proto3.makeMessageType( + "yorkie.v1.Operation.TreeEdit", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "from", kind: "message", T: TreePos }, + { no: 3, name: "to", kind: "message", T: TreePos }, + { no: 4, name: "created_at_map_by_actor", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: TimeTicket} }, + { no: 5, name: "contents", kind: "message", T: TreeNodes, repeated: true }, + { no: 7, name: "split_level", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 6, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_TreeEdit"}, +); + +/** + * @generated from message yorkie.v1.Operation.TreeStyle + */ +const Operation_TreeStyle = proto3.makeMessageType( + "yorkie.v1.Operation.TreeStyle", + () => [ + { no: 1, name: "parent_created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "from", kind: "message", T: TreePos }, + { no: 3, name: "to", kind: "message", T: TreePos }, + { no: 4, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} }, + { no: 5, name: "executed_at", kind: "message", T: TimeTicket }, + ], + {localName: "Operation_TreeStyle"}, +); + +/** + * @generated from message yorkie.v1.JSONElementSimple + */ +const JSONElementSimple = proto3.makeMessageType( + "yorkie.v1.JSONElementSimple", + () => [ + { no: 1, name: "created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 3, name: "removed_at", kind: "message", T: TimeTicket }, + { no: 4, name: "type", kind: "enum", T: proto3.getEnumType(ValueType) }, + { no: 5, name: "value", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + ], +); + +/** + * @generated from message yorkie.v1.JSONElement + */ +const JSONElement = proto3.makeMessageType( + "yorkie.v1.JSONElement", + () => [ + { no: 1, name: "json_object", kind: "message", T: JSONElement_JSONObject, oneof: "body" }, + { no: 2, name: "json_array", kind: "message", T: JSONElement_JSONArray, oneof: "body" }, + { no: 3, name: "primitive", kind: "message", T: JSONElement_Primitive, oneof: "body" }, + { no: 5, name: "text", kind: "message", T: JSONElement_Text, oneof: "body" }, + { no: 6, name: "counter", kind: "message", T: JSONElement_Counter, oneof: "body" }, + { no: 7, name: "tree", kind: "message", T: JSONElement_Tree, oneof: "body" }, + ], +); + +/** + * @generated from message yorkie.v1.JSONElement.JSONObject + */ +const JSONElement_JSONObject = proto3.makeMessageType( + "yorkie.v1.JSONElement.JSONObject", + () => [ + { no: 1, name: "nodes", kind: "message", T: RHTNode, repeated: true }, + { no: 2, name: "created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 4, name: "removed_at", kind: "message", T: TimeTicket }, + ], + {localName: "JSONElement_JSONObject"}, +); + +/** + * @generated from message yorkie.v1.JSONElement.JSONArray + */ +const JSONElement_JSONArray = proto3.makeMessageType( + "yorkie.v1.JSONElement.JSONArray", + () => [ + { no: 1, name: "nodes", kind: "message", T: RGANode, repeated: true }, + { no: 2, name: "created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 4, name: "removed_at", kind: "message", T: TimeTicket }, + ], + {localName: "JSONElement_JSONArray"}, +); + +/** + * @generated from message yorkie.v1.JSONElement.Primitive + */ +const JSONElement_Primitive = proto3.makeMessageType( + "yorkie.v1.JSONElement.Primitive", + () => [ + { no: 1, name: "type", kind: "enum", T: proto3.getEnumType(ValueType) }, + { no: 2, name: "value", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + { no: 3, name: "created_at", kind: "message", T: TimeTicket }, + { no: 4, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 5, name: "removed_at", kind: "message", T: TimeTicket }, + ], + {localName: "JSONElement_Primitive"}, +); + +/** + * @generated from message yorkie.v1.JSONElement.Text + */ +const JSONElement_Text = proto3.makeMessageType( + "yorkie.v1.JSONElement.Text", + () => [ + { no: 1, name: "nodes", kind: "message", T: TextNode, repeated: true }, + { no: 2, name: "created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 4, name: "removed_at", kind: "message", T: TimeTicket }, + ], + {localName: "JSONElement_Text"}, +); + +/** + * @generated from message yorkie.v1.JSONElement.Counter + */ +const JSONElement_Counter = proto3.makeMessageType( + "yorkie.v1.JSONElement.Counter", + () => [ + { no: 1, name: "type", kind: "enum", T: proto3.getEnumType(ValueType) }, + { no: 2, name: "value", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + { no: 3, name: "created_at", kind: "message", T: TimeTicket }, + { no: 4, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 5, name: "removed_at", kind: "message", T: TimeTicket }, + ], + {localName: "JSONElement_Counter"}, +); + +/** + * @generated from message yorkie.v1.JSONElement.Tree + */ +const JSONElement_Tree = proto3.makeMessageType( + "yorkie.v1.JSONElement.Tree", + () => [ + { no: 1, name: "nodes", kind: "message", T: TreeNode, repeated: true }, + { no: 2, name: "created_at", kind: "message", T: TimeTicket }, + { no: 3, name: "moved_at", kind: "message", T: TimeTicket }, + { no: 4, name: "removed_at", kind: "message", T: TimeTicket }, + ], + {localName: "JSONElement_Tree"}, +); + +/** + * @generated from message yorkie.v1.RHTNode + */ +const RHTNode = proto3.makeMessageType( + "yorkie.v1.RHTNode", + () => [ + { no: 1, name: "key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "element", kind: "message", T: JSONElement }, + ], +); + +/** + * @generated from message yorkie.v1.RGANode + */ +const RGANode = proto3.makeMessageType( + "yorkie.v1.RGANode", + () => [ + { no: 1, name: "next", kind: "message", T: RGANode }, + { no: 2, name: "element", kind: "message", T: JSONElement }, + ], +); + +/** + * @generated from message yorkie.v1.NodeAttr + */ +const NodeAttr = proto3.makeMessageType( + "yorkie.v1.NodeAttr", + () => [ + { no: 1, name: "value", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "updated_at", kind: "message", T: TimeTicket }, + ], +); + +/** + * @generated from message yorkie.v1.TextNode + */ +const TextNode = proto3.makeMessageType( + "yorkie.v1.TextNode", + () => [ + { no: 1, name: "id", kind: "message", T: TextNodeID }, + { no: 2, name: "value", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "removed_at", kind: "message", T: TimeTicket }, + { no: 4, name: "ins_prev_id", kind: "message", T: TextNodeID }, + { no: 5, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: NodeAttr} }, + ], +); + +/** + * @generated from message yorkie.v1.TextNodeID + */ +const TextNodeID = proto3.makeMessageType( + "yorkie.v1.TextNodeID", + () => [ + { no: 1, name: "created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "offset", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + ], +); + +/** + * @generated from message yorkie.v1.TreeNode + */ +const TreeNode = proto3.makeMessageType( + "yorkie.v1.TreeNode", + () => [ + { no: 1, name: "id", kind: "message", T: TreeNodeID }, + { no: 2, name: "type", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "value", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "removed_at", kind: "message", T: TimeTicket }, + { no: 5, name: "ins_prev_id", kind: "message", T: TreeNodeID }, + { no: 6, name: "ins_next_id", kind: "message", T: TreeNodeID }, + { no: 7, name: "depth", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 8, name: "attributes", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "message", T: NodeAttr} }, + ], +); + +/** + * @generated from message yorkie.v1.TreeNodes + */ +const TreeNodes = proto3.makeMessageType( + "yorkie.v1.TreeNodes", + () => [ + { no: 1, name: "content", kind: "message", T: TreeNode, repeated: true }, + ], +); + +/** + * @generated from message yorkie.v1.TreeNodeID + */ +const TreeNodeID = proto3.makeMessageType( + "yorkie.v1.TreeNodeID", + () => [ + { no: 1, name: "created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "offset", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + ], +); + +/** + * @generated from message yorkie.v1.TreePos + */ +const TreePos = proto3.makeMessageType( + "yorkie.v1.TreePos", + () => [ + { no: 1, name: "parent_id", kind: "message", T: TreeNodeID }, + { no: 2, name: "left_sibling_id", kind: "message", T: TreeNodeID }, + ], +); + +/** + * @generated from message yorkie.v1.User + */ +const User = proto3.makeMessageType( + "yorkie.v1.User", + () => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "username", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "created_at", kind: "message", T: Timestamp }, + ], +); + +/** + * @generated from message yorkie.v1.Project */ -proto.yorkie.v1.ChangePack.prototype.clearChangesList = function() { - return this.setChangesList([]); -}; - - -/** - * optional TimeTicket min_synced_ticket = 5; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.ChangePack.prototype.getMinSyncedTicket = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.ChangePack} returns this -*/ -proto.yorkie.v1.ChangePack.prototype.setMinSyncedTicket = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.ChangePack} returns this - */ -proto.yorkie.v1.ChangePack.prototype.clearMinSyncedTicket = function() { - return this.setMinSyncedTicket(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.ChangePack.prototype.hasMinSyncedTicket = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * optional bool is_removed = 6; - * @return {boolean} - */ -proto.yorkie.v1.ChangePack.prototype.getIsRemoved = function() { - return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 6, false)); -}; - - -/** - * @param {boolean} value - * @return {!proto.yorkie.v1.ChangePack} returns this - */ -proto.yorkie.v1.ChangePack.prototype.setIsRemoved = function(value) { - return jspb.Message.setProto3BooleanField(this, 6, value); -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.Change.repeatedFields_ = [3]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Change.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Change.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Change} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Change.toObject = function(includeInstance, msg) { - var f, obj = { - id: (f = msg.getId()) && proto.yorkie.v1.ChangeID.toObject(includeInstance, f), - message: jspb.Message.getFieldWithDefault(msg, 2, ""), - operationsList: jspb.Message.toObjectList(msg.getOperationsList(), - proto.yorkie.v1.Operation.toObject, includeInstance), - presenceChange: (f = msg.getPresenceChange()) && proto.yorkie.v1.PresenceChange.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Change} - */ -proto.yorkie.v1.Change.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Change; - return proto.yorkie.v1.Change.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Change} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Change} - */ -proto.yorkie.v1.Change.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.ChangeID; - reader.readMessage(value,proto.yorkie.v1.ChangeID.deserializeBinaryFromReader); - msg.setId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setMessage(value); - break; - case 3: - var value = new proto.yorkie.v1.Operation; - reader.readMessage(value,proto.yorkie.v1.Operation.deserializeBinaryFromReader); - msg.addOperations(value); - break; - case 4: - var value = new proto.yorkie.v1.PresenceChange; - reader.readMessage(value,proto.yorkie.v1.PresenceChange.deserializeBinaryFromReader); - msg.setPresenceChange(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Change.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Change.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Change} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Change.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getId(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.ChangeID.serializeBinaryToWriter - ); - } - f = message.getMessage(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getOperationsList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 3, - f, - proto.yorkie.v1.Operation.serializeBinaryToWriter - ); - } - f = message.getPresenceChange(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.PresenceChange.serializeBinaryToWriter - ); - } -}; - - -/** - * optional ChangeID id = 1; - * @return {?proto.yorkie.v1.ChangeID} - */ -proto.yorkie.v1.Change.prototype.getId = function() { - return /** @type{?proto.yorkie.v1.ChangeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.ChangeID, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangeID|undefined} value - * @return {!proto.yorkie.v1.Change} returns this -*/ -proto.yorkie.v1.Change.prototype.setId = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Change} returns this - */ -proto.yorkie.v1.Change.prototype.clearId = function() { - return this.setId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Change.prototype.hasId = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional string message = 2; - * @return {string} - */ -proto.yorkie.v1.Change.prototype.getMessage = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Change} returns this - */ -proto.yorkie.v1.Change.prototype.setMessage = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * repeated Operation operations = 3; - * @return {!Array} - */ -proto.yorkie.v1.Change.prototype.getOperationsList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.Operation, 3)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.Change} returns this -*/ -proto.yorkie.v1.Change.prototype.setOperationsList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 3, value); -}; - - -/** - * @param {!proto.yorkie.v1.Operation=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.Operation} - */ -proto.yorkie.v1.Change.prototype.addOperations = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 3, opt_value, proto.yorkie.v1.Operation, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.Change} returns this - */ -proto.yorkie.v1.Change.prototype.clearOperationsList = function() { - return this.setOperationsList([]); -}; - - -/** - * optional PresenceChange presence_change = 4; - * @return {?proto.yorkie.v1.PresenceChange} - */ -proto.yorkie.v1.Change.prototype.getPresenceChange = function() { - return /** @type{?proto.yorkie.v1.PresenceChange} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.PresenceChange, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.PresenceChange|undefined} value - * @return {!proto.yorkie.v1.Change} returns this -*/ -proto.yorkie.v1.Change.prototype.setPresenceChange = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Change} returns this - */ -proto.yorkie.v1.Change.prototype.clearPresenceChange = function() { - return this.setPresenceChange(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Change.prototype.hasPresenceChange = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.ChangeID.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.ChangeID.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.ChangeID} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ChangeID.toObject = function(includeInstance, msg) { - var f, obj = { - clientSeq: jspb.Message.getFieldWithDefault(msg, 1, 0), - serverSeq: jspb.Message.getFieldWithDefault(msg, 2, "0"), - lamport: jspb.Message.getFieldWithDefault(msg, 3, "0"), - actorId: msg.getActorId_asB64() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.ChangeID} - */ -proto.yorkie.v1.ChangeID.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.ChangeID; - return proto.yorkie.v1.ChangeID.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.ChangeID} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.ChangeID} - */ -proto.yorkie.v1.ChangeID.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readUint32()); - msg.setClientSeq(value); - break; - case 2: - var value = /** @type {string} */ (reader.readInt64String()); - msg.setServerSeq(value); - break; - case 3: - var value = /** @type {string} */ (reader.readInt64String()); - msg.setLamport(value); - break; - case 4: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setActorId(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.ChangeID.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.ChangeID.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.ChangeID} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ChangeID.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientSeq(); - if (f !== 0) { - writer.writeUint32( - 1, - f - ); - } - f = message.getServerSeq(); - if (parseInt(f, 10) !== 0) { - writer.writeInt64String( - 2, - f - ); - } - f = message.getLamport(); - if (parseInt(f, 10) !== 0) { - writer.writeInt64String( - 3, - f - ); - } - f = message.getActorId_asU8(); - if (f.length > 0) { - writer.writeBytes( - 4, - f - ); - } -}; - - -/** - * optional uint32 client_seq = 1; - * @return {number} - */ -proto.yorkie.v1.ChangeID.prototype.getClientSeq = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.ChangeID} returns this - */ -proto.yorkie.v1.ChangeID.prototype.setClientSeq = function(value) { - return jspb.Message.setProto3IntField(this, 1, value); -}; - - -/** - * optional int64 server_seq = 2; - * @return {string} - */ -proto.yorkie.v1.ChangeID.prototype.getServerSeq = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.ChangeID} returns this - */ -proto.yorkie.v1.ChangeID.prototype.setServerSeq = function(value) { - return jspb.Message.setProto3StringIntField(this, 2, value); -}; - - -/** - * optional int64 lamport = 3; - * @return {string} - */ -proto.yorkie.v1.ChangeID.prototype.getLamport = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "0")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.ChangeID} returns this - */ -proto.yorkie.v1.ChangeID.prototype.setLamport = function(value) { - return jspb.Message.setProto3StringIntField(this, 3, value); -}; - - -/** - * optional bytes actor_id = 4; - * @return {string} - */ -proto.yorkie.v1.ChangeID.prototype.getActorId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); -}; - - -/** - * optional bytes actor_id = 4; - * This is a type-conversion wrapper around `getActorId()` - * @return {string} - */ -proto.yorkie.v1.ChangeID.prototype.getActorId_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getActorId())); -}; - - -/** - * optional bytes actor_id = 4; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getActorId()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.ChangeID.prototype.getActorId_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getActorId())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.ChangeID} returns this - */ -proto.yorkie.v1.ChangeID.prototype.setActorId = function(value) { - return jspb.Message.setProto3BytesField(this, 4, value); -}; - - - -/** - * Oneof group definitions for this message. Each group defines the field - * numbers belonging to that group. When of these fields' value is set, all - * other fields in the group are cleared. During deserialization, if multiple - * fields are encountered for a group, only the last value seen will be kept. - * @private {!Array>} - * @const - */ -proto.yorkie.v1.Operation.oneofGroups_ = [[1,2,3,4,5,6,7,8,9,10]]; - -/** - * @enum {number} - */ -proto.yorkie.v1.Operation.BodyCase = { - BODY_NOT_SET: 0, - SET: 1, - ADD: 2, - MOVE: 3, - REMOVE: 4, - EDIT: 5, - SELECT: 6, - STYLE: 7, - INCREASE: 8, - TREE_EDIT: 9, - TREE_STYLE: 10 -}; - -/** - * @return {proto.yorkie.v1.Operation.BodyCase} - */ -proto.yorkie.v1.Operation.prototype.getBodyCase = function() { - return /** @type {proto.yorkie.v1.Operation.BodyCase} */(jspb.Message.computeOneofCase(this, proto.yorkie.v1.Operation.oneofGroups_[0])); -}; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.toObject = function(includeInstance, msg) { - var f, obj = { - set: (f = msg.getSet()) && proto.yorkie.v1.Operation.Set.toObject(includeInstance, f), - add: (f = msg.getAdd()) && proto.yorkie.v1.Operation.Add.toObject(includeInstance, f), - move: (f = msg.getMove()) && proto.yorkie.v1.Operation.Move.toObject(includeInstance, f), - remove: (f = msg.getRemove()) && proto.yorkie.v1.Operation.Remove.toObject(includeInstance, f), - edit: (f = msg.getEdit()) && proto.yorkie.v1.Operation.Edit.toObject(includeInstance, f), - select: (f = msg.getSelect()) && proto.yorkie.v1.Operation.Select.toObject(includeInstance, f), - style: (f = msg.getStyle()) && proto.yorkie.v1.Operation.Style.toObject(includeInstance, f), - increase: (f = msg.getIncrease()) && proto.yorkie.v1.Operation.Increase.toObject(includeInstance, f), - treeEdit: (f = msg.getTreeEdit()) && proto.yorkie.v1.Operation.TreeEdit.toObject(includeInstance, f), - treeStyle: (f = msg.getTreeStyle()) && proto.yorkie.v1.Operation.TreeStyle.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation} - */ -proto.yorkie.v1.Operation.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation; - return proto.yorkie.v1.Operation.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation} - */ -proto.yorkie.v1.Operation.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.Operation.Set; - reader.readMessage(value,proto.yorkie.v1.Operation.Set.deserializeBinaryFromReader); - msg.setSet(value); - break; - case 2: - var value = new proto.yorkie.v1.Operation.Add; - reader.readMessage(value,proto.yorkie.v1.Operation.Add.deserializeBinaryFromReader); - msg.setAdd(value); - break; - case 3: - var value = new proto.yorkie.v1.Operation.Move; - reader.readMessage(value,proto.yorkie.v1.Operation.Move.deserializeBinaryFromReader); - msg.setMove(value); - break; - case 4: - var value = new proto.yorkie.v1.Operation.Remove; - reader.readMessage(value,proto.yorkie.v1.Operation.Remove.deserializeBinaryFromReader); - msg.setRemove(value); - break; - case 5: - var value = new proto.yorkie.v1.Operation.Edit; - reader.readMessage(value,proto.yorkie.v1.Operation.Edit.deserializeBinaryFromReader); - msg.setEdit(value); - break; - case 6: - var value = new proto.yorkie.v1.Operation.Select; - reader.readMessage(value,proto.yorkie.v1.Operation.Select.deserializeBinaryFromReader); - msg.setSelect(value); - break; - case 7: - var value = new proto.yorkie.v1.Operation.Style; - reader.readMessage(value,proto.yorkie.v1.Operation.Style.deserializeBinaryFromReader); - msg.setStyle(value); - break; - case 8: - var value = new proto.yorkie.v1.Operation.Increase; - reader.readMessage(value,proto.yorkie.v1.Operation.Increase.deserializeBinaryFromReader); - msg.setIncrease(value); - break; - case 9: - var value = new proto.yorkie.v1.Operation.TreeEdit; - reader.readMessage(value,proto.yorkie.v1.Operation.TreeEdit.deserializeBinaryFromReader); - msg.setTreeEdit(value); - break; - case 10: - var value = new proto.yorkie.v1.Operation.TreeStyle; - reader.readMessage(value,proto.yorkie.v1.Operation.TreeStyle.deserializeBinaryFromReader); - msg.setTreeStyle(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getSet(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.Operation.Set.serializeBinaryToWriter - ); - } - f = message.getAdd(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.Operation.Add.serializeBinaryToWriter - ); - } - f = message.getMove(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.Operation.Move.serializeBinaryToWriter - ); - } - f = message.getRemove(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.Operation.Remove.serializeBinaryToWriter - ); - } - f = message.getEdit(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.Operation.Edit.serializeBinaryToWriter - ); - } - f = message.getSelect(); - if (f != null) { - writer.writeMessage( - 6, - f, - proto.yorkie.v1.Operation.Select.serializeBinaryToWriter - ); - } - f = message.getStyle(); - if (f != null) { - writer.writeMessage( - 7, - f, - proto.yorkie.v1.Operation.Style.serializeBinaryToWriter - ); - } - f = message.getIncrease(); - if (f != null) { - writer.writeMessage( - 8, - f, - proto.yorkie.v1.Operation.Increase.serializeBinaryToWriter - ); - } - f = message.getTreeEdit(); - if (f != null) { - writer.writeMessage( - 9, - f, - proto.yorkie.v1.Operation.TreeEdit.serializeBinaryToWriter - ); - } - f = message.getTreeStyle(); - if (f != null) { - writer.writeMessage( - 10, - f, - proto.yorkie.v1.Operation.TreeStyle.serializeBinaryToWriter - ); - } -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Set.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Set.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Set} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Set.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - key: jspb.Message.getFieldWithDefault(msg, 2, ""), - value: (f = msg.getValue()) && proto.yorkie.v1.JSONElementSimple.toObject(includeInstance, f), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Set} - */ -proto.yorkie.v1.Operation.Set.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Set; - return proto.yorkie.v1.Operation.Set.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Set} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Set} - */ -proto.yorkie.v1.Operation.Set.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setKey(value); - break; - case 3: - var value = new proto.yorkie.v1.JSONElementSimple; - reader.readMessage(value,proto.yorkie.v1.JSONElementSimple.deserializeBinaryFromReader); - msg.setValue(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Set.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Set.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Set} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Set.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getKey(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getValue(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.JSONElementSimple.serializeBinaryToWriter - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Set.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Set} returns this -*/ -proto.yorkie.v1.Operation.Set.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Set} returns this - */ -proto.yorkie.v1.Operation.Set.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Set.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional string key = 2; - * @return {string} - */ -proto.yorkie.v1.Operation.Set.prototype.getKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Operation.Set} returns this - */ -proto.yorkie.v1.Operation.Set.prototype.setKey = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional JSONElementSimple value = 3; - * @return {?proto.yorkie.v1.JSONElementSimple} - */ -proto.yorkie.v1.Operation.Set.prototype.getValue = function() { - return /** @type{?proto.yorkie.v1.JSONElementSimple} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElementSimple, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElementSimple|undefined} value - * @return {!proto.yorkie.v1.Operation.Set} returns this -*/ -proto.yorkie.v1.Operation.Set.prototype.setValue = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Set} returns this - */ -proto.yorkie.v1.Operation.Set.prototype.clearValue = function() { - return this.setValue(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Set.prototype.hasValue = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket executed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Set.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Set} returns this -*/ -proto.yorkie.v1.Operation.Set.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Set} returns this - */ -proto.yorkie.v1.Operation.Set.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Set.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Add.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Add.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Add} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Add.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - prevCreatedAt: (f = msg.getPrevCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - value: (f = msg.getValue()) && proto.yorkie.v1.JSONElementSimple.toObject(includeInstance, f), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Add} - */ -proto.yorkie.v1.Operation.Add.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Add; - return proto.yorkie.v1.Operation.Add.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Add} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Add} - */ -proto.yorkie.v1.Operation.Add.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setPrevCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.JSONElementSimple; - reader.readMessage(value,proto.yorkie.v1.JSONElementSimple.deserializeBinaryFromReader); - msg.setValue(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Add.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Add.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Add} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Add.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getPrevCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getValue(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.JSONElementSimple.serializeBinaryToWriter - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Add.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Add} returns this -*/ -proto.yorkie.v1.Operation.Add.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Add} returns this - */ -proto.yorkie.v1.Operation.Add.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Add.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TimeTicket prev_created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Add.prototype.getPrevCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Add} returns this -*/ -proto.yorkie.v1.Operation.Add.prototype.setPrevCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Add} returns this - */ -proto.yorkie.v1.Operation.Add.prototype.clearPrevCreatedAt = function() { - return this.setPrevCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Add.prototype.hasPrevCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional JSONElementSimple value = 3; - * @return {?proto.yorkie.v1.JSONElementSimple} - */ -proto.yorkie.v1.Operation.Add.prototype.getValue = function() { - return /** @type{?proto.yorkie.v1.JSONElementSimple} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElementSimple, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElementSimple|undefined} value - * @return {!proto.yorkie.v1.Operation.Add} returns this -*/ -proto.yorkie.v1.Operation.Add.prototype.setValue = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Add} returns this - */ -proto.yorkie.v1.Operation.Add.prototype.clearValue = function() { - return this.setValue(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Add.prototype.hasValue = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket executed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Add.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Add} returns this -*/ -proto.yorkie.v1.Operation.Add.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Add} returns this - */ -proto.yorkie.v1.Operation.Add.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Add.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Move.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Move.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Move} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Move.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - prevCreatedAt: (f = msg.getPrevCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Move} - */ -proto.yorkie.v1.Operation.Move.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Move; - return proto.yorkie.v1.Operation.Move.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Move} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Move} - */ -proto.yorkie.v1.Operation.Move.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setPrevCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Move.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Move.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Move} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Move.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getPrevCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Move.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Move} returns this -*/ -proto.yorkie.v1.Operation.Move.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Move} returns this - */ -proto.yorkie.v1.Operation.Move.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Move.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TimeTicket prev_created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Move.prototype.getPrevCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Move} returns this -*/ -proto.yorkie.v1.Operation.Move.prototype.setPrevCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Move} returns this - */ -proto.yorkie.v1.Operation.Move.prototype.clearPrevCreatedAt = function() { - return this.setPrevCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Move.prototype.hasPrevCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket created_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Move.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Move} returns this -*/ -proto.yorkie.v1.Operation.Move.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Move} returns this - */ -proto.yorkie.v1.Operation.Move.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Move.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket executed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Move.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Move} returns this -*/ -proto.yorkie.v1.Operation.Move.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Move} returns this - */ -proto.yorkie.v1.Operation.Move.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Move.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Remove.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Remove.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Remove} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Remove.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Remove} - */ -proto.yorkie.v1.Operation.Remove.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Remove; - return proto.yorkie.v1.Operation.Remove.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Remove} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Remove} - */ -proto.yorkie.v1.Operation.Remove.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Remove.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Remove.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Remove} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Remove.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Remove.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Remove} returns this -*/ -proto.yorkie.v1.Operation.Remove.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Remove} returns this - */ -proto.yorkie.v1.Operation.Remove.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Remove.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TimeTicket created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Remove.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Remove} returns this -*/ -proto.yorkie.v1.Operation.Remove.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Remove} returns this - */ -proto.yorkie.v1.Operation.Remove.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Remove.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket executed_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Remove.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Remove} returns this -*/ -proto.yorkie.v1.Operation.Remove.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Remove} returns this - */ -proto.yorkie.v1.Operation.Remove.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Remove.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Edit.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Edit.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Edit} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Edit.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - from: (f = msg.getFrom()) && proto.yorkie.v1.TextNodePos.toObject(includeInstance, f), - to: (f = msg.getTo()) && proto.yorkie.v1.TextNodePos.toObject(includeInstance, f), - createdAtMapByActorMap: (f = msg.getCreatedAtMapByActorMap()) ? f.toObject(includeInstance, proto.yorkie.v1.TimeTicket.toObject) : [], - content: jspb.Message.getFieldWithDefault(msg, 5, ""), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, undefined) : [] - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Edit} - */ -proto.yorkie.v1.Operation.Edit.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Edit; - return proto.yorkie.v1.Operation.Edit.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Edit} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Edit} - */ -proto.yorkie.v1.Operation.Edit.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TextNodePos; - reader.readMessage(value,proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader); - msg.setFrom(value); - break; - case 3: - var value = new proto.yorkie.v1.TextNodePos; - reader.readMessage(value,proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader); - msg.setTo(value); - break; - case 4: - var value = msg.getCreatedAtMapByActorMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader, "", new proto.yorkie.v1.TimeTicket()); - }); - break; - case 5: - var value = /** @type {string} */ (reader.readString()); - msg.setContent(value); - break; - case 6: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - case 7: - var value = msg.getAttributesMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); - }); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Edit.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Edit.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Edit} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Edit.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getFrom(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter - ); - } - f = message.getTo(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter - ); - } - f = message.getCreatedAtMapByActorMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(4, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.TimeTicket.serializeBinaryToWriter); - } - f = message.getContent(); - if (f.length > 0) { - writer.writeString( - 5, - f - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 6, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getAttributesMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(7, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Edit.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Edit} returns this -*/ -proto.yorkie.v1.Operation.Edit.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Edit.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TextNodePos from = 2; - * @return {?proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.Operation.Edit.prototype.getFrom = function() { - return /** @type{?proto.yorkie.v1.TextNodePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodePos, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodePos|undefined} value - * @return {!proto.yorkie.v1.Operation.Edit} returns this -*/ -proto.yorkie.v1.Operation.Edit.prototype.setFrom = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.clearFrom = function() { - return this.setFrom(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Edit.prototype.hasFrom = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TextNodePos to = 3; - * @return {?proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.Operation.Edit.prototype.getTo = function() { - return /** @type{?proto.yorkie.v1.TextNodePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodePos, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodePos|undefined} value - * @return {!proto.yorkie.v1.Operation.Edit} returns this -*/ -proto.yorkie.v1.Operation.Edit.prototype.setTo = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.clearTo = function() { - return this.setTo(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Edit.prototype.hasTo = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * map created_at_map_by_actor = 4; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Operation.Edit.prototype.getCreatedAtMapByActorMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 4, opt_noLazyCreate, - proto.yorkie.v1.TimeTicket)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.clearCreatedAtMapByActorMap = function() { - this.getCreatedAtMapByActorMap().clear(); - return this; -}; - - -/** - * optional string content = 5; - * @return {string} - */ -proto.yorkie.v1.Operation.Edit.prototype.getContent = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.setContent = function(value) { - return jspb.Message.setProto3StringField(this, 5, value); -}; - - -/** - * optional TimeTicket executed_at = 6; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Edit.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 6)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Edit} returns this -*/ -proto.yorkie.v1.Operation.Edit.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 6, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Edit.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 6) != null; -}; - - -/** - * map attributes = 7; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Operation.Edit.prototype.getAttributesMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 7, opt_noLazyCreate, - null)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Operation.Edit} returns this - */ -proto.yorkie.v1.Operation.Edit.prototype.clearAttributesMap = function() { - this.getAttributesMap().clear(); - return this; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Select.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Select.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Select} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Select.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - from: (f = msg.getFrom()) && proto.yorkie.v1.TextNodePos.toObject(includeInstance, f), - to: (f = msg.getTo()) && proto.yorkie.v1.TextNodePos.toObject(includeInstance, f), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Select} - */ -proto.yorkie.v1.Operation.Select.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Select; - return proto.yorkie.v1.Operation.Select.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Select} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Select} - */ -proto.yorkie.v1.Operation.Select.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TextNodePos; - reader.readMessage(value,proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader); - msg.setFrom(value); - break; - case 3: - var value = new proto.yorkie.v1.TextNodePos; - reader.readMessage(value,proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader); - msg.setTo(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Select.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Select.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Select} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Select.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getFrom(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter - ); - } - f = message.getTo(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Select.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Select} returns this -*/ -proto.yorkie.v1.Operation.Select.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Select} returns this - */ -proto.yorkie.v1.Operation.Select.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Select.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TextNodePos from = 2; - * @return {?proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.Operation.Select.prototype.getFrom = function() { - return /** @type{?proto.yorkie.v1.TextNodePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodePos, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodePos|undefined} value - * @return {!proto.yorkie.v1.Operation.Select} returns this -*/ -proto.yorkie.v1.Operation.Select.prototype.setFrom = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Select} returns this - */ -proto.yorkie.v1.Operation.Select.prototype.clearFrom = function() { - return this.setFrom(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Select.prototype.hasFrom = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TextNodePos to = 3; - * @return {?proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.Operation.Select.prototype.getTo = function() { - return /** @type{?proto.yorkie.v1.TextNodePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodePos, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodePos|undefined} value - * @return {!proto.yorkie.v1.Operation.Select} returns this -*/ -proto.yorkie.v1.Operation.Select.prototype.setTo = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Select} returns this - */ -proto.yorkie.v1.Operation.Select.prototype.clearTo = function() { - return this.setTo(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Select.prototype.hasTo = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket executed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Select.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Select} returns this -*/ -proto.yorkie.v1.Operation.Select.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Select} returns this - */ -proto.yorkie.v1.Operation.Select.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Select.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Style.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Style.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Style} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Style.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - from: (f = msg.getFrom()) && proto.yorkie.v1.TextNodePos.toObject(includeInstance, f), - to: (f = msg.getTo()) && proto.yorkie.v1.TextNodePos.toObject(includeInstance, f), - attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, undefined) : [], - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - createdAtMapByActorMap: (f = msg.getCreatedAtMapByActorMap()) ? f.toObject(includeInstance, proto.yorkie.v1.TimeTicket.toObject) : [] - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Style} - */ -proto.yorkie.v1.Operation.Style.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Style; - return proto.yorkie.v1.Operation.Style.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Style} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Style} - */ -proto.yorkie.v1.Operation.Style.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TextNodePos; - reader.readMessage(value,proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader); - msg.setFrom(value); - break; - case 3: - var value = new proto.yorkie.v1.TextNodePos; - reader.readMessage(value,proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader); - msg.setTo(value); - break; - case 4: - var value = msg.getAttributesMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); - }); - break; - case 5: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - case 6: - var value = msg.getCreatedAtMapByActorMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader, "", new proto.yorkie.v1.TimeTicket()); - }); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Style.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Style.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Style} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Style.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getFrom(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter - ); - } - f = message.getTo(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter - ); - } - f = message.getAttributesMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(4, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getCreatedAtMapByActorMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(6, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.TimeTicket.serializeBinaryToWriter); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Style.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Style} returns this -*/ -proto.yorkie.v1.Operation.Style.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Style} returns this - */ -proto.yorkie.v1.Operation.Style.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Style.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TextNodePos from = 2; - * @return {?proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.Operation.Style.prototype.getFrom = function() { - return /** @type{?proto.yorkie.v1.TextNodePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodePos, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodePos|undefined} value - * @return {!proto.yorkie.v1.Operation.Style} returns this -*/ -proto.yorkie.v1.Operation.Style.prototype.setFrom = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Style} returns this - */ -proto.yorkie.v1.Operation.Style.prototype.clearFrom = function() { - return this.setFrom(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Style.prototype.hasFrom = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TextNodePos to = 3; - * @return {?proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.Operation.Style.prototype.getTo = function() { - return /** @type{?proto.yorkie.v1.TextNodePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodePos, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodePos|undefined} value - * @return {!proto.yorkie.v1.Operation.Style} returns this -*/ -proto.yorkie.v1.Operation.Style.prototype.setTo = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Style} returns this - */ -proto.yorkie.v1.Operation.Style.prototype.clearTo = function() { - return this.setTo(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Style.prototype.hasTo = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * map attributes = 4; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Operation.Style.prototype.getAttributesMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 4, opt_noLazyCreate, - null)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Operation.Style} returns this - */ -proto.yorkie.v1.Operation.Style.prototype.clearAttributesMap = function() { - this.getAttributesMap().clear(); - return this; -}; - - -/** - * optional TimeTicket executed_at = 5; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Style.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Style} returns this -*/ -proto.yorkie.v1.Operation.Style.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Style} returns this - */ -proto.yorkie.v1.Operation.Style.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Style.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * map created_at_map_by_actor = 6; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Operation.Style.prototype.getCreatedAtMapByActorMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 6, opt_noLazyCreate, - proto.yorkie.v1.TimeTicket)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Operation.Style} returns this - */ -proto.yorkie.v1.Operation.Style.prototype.clearCreatedAtMapByActorMap = function() { - this.getCreatedAtMapByActorMap().clear(); - return this; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.Increase.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.Increase.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.Increase} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Increase.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - value: (f = msg.getValue()) && proto.yorkie.v1.JSONElementSimple.toObject(includeInstance, f), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.Increase} - */ -proto.yorkie.v1.Operation.Increase.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.Increase; - return proto.yorkie.v1.Operation.Increase.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.Increase} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.Increase} - */ -proto.yorkie.v1.Operation.Increase.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.JSONElementSimple; - reader.readMessage(value,proto.yorkie.v1.JSONElementSimple.deserializeBinaryFromReader); - msg.setValue(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.Increase.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.Increase.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.Increase} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.Increase.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getValue(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.JSONElementSimple.serializeBinaryToWriter - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Increase.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Increase} returns this -*/ -proto.yorkie.v1.Operation.Increase.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Increase} returns this - */ -proto.yorkie.v1.Operation.Increase.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Increase.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional JSONElementSimple value = 2; - * @return {?proto.yorkie.v1.JSONElementSimple} - */ -proto.yorkie.v1.Operation.Increase.prototype.getValue = function() { - return /** @type{?proto.yorkie.v1.JSONElementSimple} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElementSimple, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElementSimple|undefined} value - * @return {!proto.yorkie.v1.Operation.Increase} returns this -*/ -proto.yorkie.v1.Operation.Increase.prototype.setValue = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Increase} returns this - */ -proto.yorkie.v1.Operation.Increase.prototype.clearValue = function() { - return this.setValue(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Increase.prototype.hasValue = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket executed_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.Increase.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.Increase} returns this -*/ -proto.yorkie.v1.Operation.Increase.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.Increase} returns this - */ -proto.yorkie.v1.Operation.Increase.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.Increase.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.Operation.TreeEdit.repeatedFields_ = [5]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.TreeEdit.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.TreeEdit} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.TreeEdit.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - from: (f = msg.getFrom()) && proto.yorkie.v1.TreePos.toObject(includeInstance, f), - to: (f = msg.getTo()) && proto.yorkie.v1.TreePos.toObject(includeInstance, f), - createdAtMapByActorMap: (f = msg.getCreatedAtMapByActorMap()) ? f.toObject(includeInstance, proto.yorkie.v1.TimeTicket.toObject) : [], - contentsList: jspb.Message.toObjectList(msg.getContentsList(), - proto.yorkie.v1.TreeNodes.toObject, includeInstance), - splitLevel: jspb.Message.getFieldWithDefault(msg, 7, 0), - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.TreeEdit} - */ -proto.yorkie.v1.Operation.TreeEdit.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.TreeEdit; - return proto.yorkie.v1.Operation.TreeEdit.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.TreeEdit} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.TreeEdit} - */ -proto.yorkie.v1.Operation.TreeEdit.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TreePos; - reader.readMessage(value,proto.yorkie.v1.TreePos.deserializeBinaryFromReader); - msg.setFrom(value); - break; - case 3: - var value = new proto.yorkie.v1.TreePos; - reader.readMessage(value,proto.yorkie.v1.TreePos.deserializeBinaryFromReader); - msg.setTo(value); - break; - case 4: - var value = msg.getCreatedAtMapByActorMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader, "", new proto.yorkie.v1.TimeTicket()); - }); - break; - case 5: - var value = new proto.yorkie.v1.TreeNodes; - reader.readMessage(value,proto.yorkie.v1.TreeNodes.deserializeBinaryFromReader); - msg.addContents(value); - break; - case 7: - var value = /** @type {number} */ (reader.readInt32()); - msg.setSplitLevel(value); - break; - case 6: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.TreeEdit.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.TreeEdit} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.TreeEdit.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getFrom(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TreePos.serializeBinaryToWriter - ); - } - f = message.getTo(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TreePos.serializeBinaryToWriter - ); - } - f = message.getCreatedAtMapByActorMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(4, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.TimeTicket.serializeBinaryToWriter); - } - f = message.getContentsList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 5, - f, - proto.yorkie.v1.TreeNodes.serializeBinaryToWriter - ); - } - f = message.getSplitLevel(); - if (f !== 0) { - writer.writeInt32( - 7, - f - ); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 6, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this -*/ -proto.yorkie.v1.Operation.TreeEdit.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TreePos from = 2; - * @return {?proto.yorkie.v1.TreePos} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getFrom = function() { - return /** @type{?proto.yorkie.v1.TreePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreePos, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TreePos|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this -*/ -proto.yorkie.v1.Operation.TreeEdit.prototype.setFrom = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.clearFrom = function() { - return this.setFrom(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.hasFrom = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TreePos to = 3; - * @return {?proto.yorkie.v1.TreePos} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getTo = function() { - return /** @type{?proto.yorkie.v1.TreePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreePos, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TreePos|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this -*/ -proto.yorkie.v1.Operation.TreeEdit.prototype.setTo = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.clearTo = function() { - return this.setTo(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.hasTo = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * map created_at_map_by_actor = 4; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getCreatedAtMapByActorMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 4, opt_noLazyCreate, - proto.yorkie.v1.TimeTicket)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.clearCreatedAtMapByActorMap = function() { - this.getCreatedAtMapByActorMap().clear(); - return this; -}; - - -/** - * repeated TreeNodes contents = 5; - * @return {!Array} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getContentsList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.TreeNodes, 5)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this -*/ -proto.yorkie.v1.Operation.TreeEdit.prototype.setContentsList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 5, value); -}; - - -/** - * @param {!proto.yorkie.v1.TreeNodes=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.TreeNodes} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.addContents = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 5, opt_value, proto.yorkie.v1.TreeNodes, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.clearContentsList = function() { - return this.setContentsList([]); -}; - - -/** - * optional int32 split_level = 7; - * @return {number} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getSplitLevel = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.setSplitLevel = function(value) { - return jspb.Message.setProto3IntField(this, 7, value); -}; - - -/** - * optional TimeTicket executed_at = 6; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 6)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this -*/ -proto.yorkie.v1.Operation.TreeEdit.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 6, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeEdit} returns this - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeEdit.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 6) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Operation.TreeStyle.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Operation.TreeStyle} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.TreeStyle.toObject = function(includeInstance, msg) { - var f, obj = { - parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - from: (f = msg.getFrom()) && proto.yorkie.v1.TreePos.toObject(includeInstance, f), - to: (f = msg.getTo()) && proto.yorkie.v1.TreePos.toObject(includeInstance, f), - attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, undefined) : [], - executedAt: (f = msg.getExecutedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Operation.TreeStyle} - */ -proto.yorkie.v1.Operation.TreeStyle.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Operation.TreeStyle; - return proto.yorkie.v1.Operation.TreeStyle.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Operation.TreeStyle} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Operation.TreeStyle} - */ -proto.yorkie.v1.Operation.TreeStyle.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setParentCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TreePos; - reader.readMessage(value,proto.yorkie.v1.TreePos.deserializeBinaryFromReader); - msg.setFrom(value); - break; - case 3: - var value = new proto.yorkie.v1.TreePos; - reader.readMessage(value,proto.yorkie.v1.TreePos.deserializeBinaryFromReader); - msg.setTo(value); - break; - case 4: - var value = msg.getAttributesMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); - }); - break; - case 5: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setExecutedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Operation.TreeStyle.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Operation.TreeStyle} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Operation.TreeStyle.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getFrom(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TreePos.serializeBinaryToWriter - ); - } - f = message.getTo(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TreePos.serializeBinaryToWriter - ); - } - f = message.getAttributesMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(4, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); - } - f = message.getExecutedAt(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TimeTicket parent_created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.getParentCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this -*/ -proto.yorkie.v1.Operation.TreeStyle.prototype.setParentCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.clearParentCreatedAt = function() { - return this.setParentCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.hasParentCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TreePos from = 2; - * @return {?proto.yorkie.v1.TreePos} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.getFrom = function() { - return /** @type{?proto.yorkie.v1.TreePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreePos, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TreePos|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this -*/ -proto.yorkie.v1.Operation.TreeStyle.prototype.setFrom = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.clearFrom = function() { - return this.setFrom(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.hasFrom = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TreePos to = 3; - * @return {?proto.yorkie.v1.TreePos} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.getTo = function() { - return /** @type{?proto.yorkie.v1.TreePos} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreePos, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TreePos|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this -*/ -proto.yorkie.v1.Operation.TreeStyle.prototype.setTo = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.clearTo = function() { - return this.setTo(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.hasTo = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * map attributes = 4; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.getAttributesMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 4, opt_noLazyCreate, - null)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.clearAttributesMap = function() { - this.getAttributesMap().clear(); - return this; -}; - - -/** - * optional TimeTicket executed_at = 5; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.getExecutedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this -*/ -proto.yorkie.v1.Operation.TreeStyle.prototype.setExecutedAt = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation.TreeStyle} returns this - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.clearExecutedAt = function() { - return this.setExecutedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.TreeStyle.prototype.hasExecutedAt = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * optional Set set = 1; - * @return {?proto.yorkie.v1.Operation.Set} - */ -proto.yorkie.v1.Operation.prototype.getSet = function() { - return /** @type{?proto.yorkie.v1.Operation.Set} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Set, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Set|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setSet = function(value) { - return jspb.Message.setOneofWrapperField(this, 1, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearSet = function() { - return this.setSet(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasSet = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional Add add = 2; - * @return {?proto.yorkie.v1.Operation.Add} - */ -proto.yorkie.v1.Operation.prototype.getAdd = function() { - return /** @type{?proto.yorkie.v1.Operation.Add} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Add, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Add|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setAdd = function(value) { - return jspb.Message.setOneofWrapperField(this, 2, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearAdd = function() { - return this.setAdd(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasAdd = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional Move move = 3; - * @return {?proto.yorkie.v1.Operation.Move} - */ -proto.yorkie.v1.Operation.prototype.getMove = function() { - return /** @type{?proto.yorkie.v1.Operation.Move} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Move, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Move|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setMove = function(value) { - return jspb.Message.setOneofWrapperField(this, 3, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearMove = function() { - return this.setMove(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasMove = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional Remove remove = 4; - * @return {?proto.yorkie.v1.Operation.Remove} - */ -proto.yorkie.v1.Operation.prototype.getRemove = function() { - return /** @type{?proto.yorkie.v1.Operation.Remove} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Remove, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Remove|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setRemove = function(value) { - return jspb.Message.setOneofWrapperField(this, 4, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearRemove = function() { - return this.setRemove(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasRemove = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * optional Edit edit = 5; - * @return {?proto.yorkie.v1.Operation.Edit} - */ -proto.yorkie.v1.Operation.prototype.getEdit = function() { - return /** @type{?proto.yorkie.v1.Operation.Edit} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Edit, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Edit|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setEdit = function(value) { - return jspb.Message.setOneofWrapperField(this, 5, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearEdit = function() { - return this.setEdit(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasEdit = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * optional Select select = 6; - * @return {?proto.yorkie.v1.Operation.Select} - */ -proto.yorkie.v1.Operation.prototype.getSelect = function() { - return /** @type{?proto.yorkie.v1.Operation.Select} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Select, 6)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Select|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setSelect = function(value) { - return jspb.Message.setOneofWrapperField(this, 6, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearSelect = function() { - return this.setSelect(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasSelect = function() { - return jspb.Message.getField(this, 6) != null; -}; - - -/** - * optional Style style = 7; - * @return {?proto.yorkie.v1.Operation.Style} - */ -proto.yorkie.v1.Operation.prototype.getStyle = function() { - return /** @type{?proto.yorkie.v1.Operation.Style} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Style, 7)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Style|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setStyle = function(value) { - return jspb.Message.setOneofWrapperField(this, 7, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearStyle = function() { - return this.setStyle(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasStyle = function() { - return jspb.Message.getField(this, 7) != null; -}; - - -/** - * optional Increase increase = 8; - * @return {?proto.yorkie.v1.Operation.Increase} - */ -proto.yorkie.v1.Operation.prototype.getIncrease = function() { - return /** @type{?proto.yorkie.v1.Operation.Increase} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.Increase, 8)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.Increase|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setIncrease = function(value) { - return jspb.Message.setOneofWrapperField(this, 8, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearIncrease = function() { - return this.setIncrease(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasIncrease = function() { - return jspb.Message.getField(this, 8) != null; -}; - - -/** - * optional TreeEdit tree_edit = 9; - * @return {?proto.yorkie.v1.Operation.TreeEdit} - */ -proto.yorkie.v1.Operation.prototype.getTreeEdit = function() { - return /** @type{?proto.yorkie.v1.Operation.TreeEdit} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.TreeEdit, 9)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.TreeEdit|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setTreeEdit = function(value) { - return jspb.Message.setOneofWrapperField(this, 9, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearTreeEdit = function() { - return this.setTreeEdit(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasTreeEdit = function() { - return jspb.Message.getField(this, 9) != null; -}; - - -/** - * optional TreeStyle tree_style = 10; - * @return {?proto.yorkie.v1.Operation.TreeStyle} - */ -proto.yorkie.v1.Operation.prototype.getTreeStyle = function() { - return /** @type{?proto.yorkie.v1.Operation.TreeStyle} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Operation.TreeStyle, 10)); -}; - - -/** - * @param {?proto.yorkie.v1.Operation.TreeStyle|undefined} value - * @return {!proto.yorkie.v1.Operation} returns this -*/ -proto.yorkie.v1.Operation.prototype.setTreeStyle = function(value) { - return jspb.Message.setOneofWrapperField(this, 10, proto.yorkie.v1.Operation.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Operation} returns this - */ -proto.yorkie.v1.Operation.prototype.clearTreeStyle = function() { - return this.setTreeStyle(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Operation.prototype.hasTreeStyle = function() { - return jspb.Message.getField(this, 10) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElementSimple.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElementSimple.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElementSimple} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElementSimple.toObject = function(includeInstance, msg) { - var f, obj = { - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - type: jspb.Message.getFieldWithDefault(msg, 4, 0), - value: msg.getValue_asB64() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElementSimple} - */ -proto.yorkie.v1.JSONElementSimple.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElementSimple; - return proto.yorkie.v1.JSONElementSimple.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElementSimple} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElementSimple} - */ -proto.yorkie.v1.JSONElementSimple.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - case 4: - var value = /** @type {!proto.yorkie.v1.ValueType} */ (reader.readEnum()); - msg.setType(value); - break; - case 5: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setValue(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElementSimple.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElementSimple.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElementSimple} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElementSimple.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 4, - f - ); - } - f = message.getValue_asU8(); - if (f.length > 0) { - writer.writeBytes( - 5, - f - ); - } -}; - - -/** - * optional TimeTicket created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElementSimple} returns this -*/ -proto.yorkie.v1.JSONElementSimple.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElementSimple} returns this - */ -proto.yorkie.v1.JSONElementSimple.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElementSimple.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TimeTicket moved_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElementSimple} returns this -*/ -proto.yorkie.v1.JSONElementSimple.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElementSimple} returns this - */ -proto.yorkie.v1.JSONElementSimple.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElementSimple.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket removed_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElementSimple} returns this -*/ -proto.yorkie.v1.JSONElementSimple.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElementSimple} returns this - */ -proto.yorkie.v1.JSONElementSimple.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElementSimple.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional ValueType type = 4; - * @return {!proto.yorkie.v1.ValueType} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getType = function() { - return /** @type {!proto.yorkie.v1.ValueType} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); -}; - - -/** - * @param {!proto.yorkie.v1.ValueType} value - * @return {!proto.yorkie.v1.JSONElementSimple} returns this - */ -proto.yorkie.v1.JSONElementSimple.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 4, value); -}; - - -/** - * optional bytes value = 5; - * @return {string} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); -}; - - -/** - * optional bytes value = 5; - * This is a type-conversion wrapper around `getValue()` - * @return {string} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getValue_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getValue())); -}; - - -/** - * optional bytes value = 5; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getValue()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElementSimple.prototype.getValue_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getValue())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.JSONElementSimple} returns this - */ -proto.yorkie.v1.JSONElementSimple.prototype.setValue = function(value) { - return jspb.Message.setProto3BytesField(this, 5, value); -}; - - - -/** - * Oneof group definitions for this message. Each group defines the field - * numbers belonging to that group. When of these fields' value is set, all - * other fields in the group are cleared. During deserialization, if multiple - * fields are encountered for a group, only the last value seen will be kept. - * @private {!Array>} - * @const - */ -proto.yorkie.v1.JSONElement.oneofGroups_ = [[1,2,3,5,6,7]]; - -/** - * @enum {number} - */ -proto.yorkie.v1.JSONElement.BodyCase = { - BODY_NOT_SET: 0, - JSON_OBJECT: 1, - JSON_ARRAY: 2, - PRIMITIVE: 3, - TEXT: 5, - COUNTER: 6, - TREE: 7 -}; - -/** - * @return {proto.yorkie.v1.JSONElement.BodyCase} - */ -proto.yorkie.v1.JSONElement.prototype.getBodyCase = function() { - return /** @type {proto.yorkie.v1.JSONElement.BodyCase} */(jspb.Message.computeOneofCase(this, proto.yorkie.v1.JSONElement.oneofGroups_[0])); -}; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.toObject = function(includeInstance, msg) { - var f, obj = { - jsonObject: (f = msg.getJsonObject()) && proto.yorkie.v1.JSONElement.JSONObject.toObject(includeInstance, f), - jsonArray: (f = msg.getJsonArray()) && proto.yorkie.v1.JSONElement.JSONArray.toObject(includeInstance, f), - primitive: (f = msg.getPrimitive()) && proto.yorkie.v1.JSONElement.Primitive.toObject(includeInstance, f), - text: (f = msg.getText()) && proto.yorkie.v1.JSONElement.Text.toObject(includeInstance, f), - counter: (f = msg.getCounter()) && proto.yorkie.v1.JSONElement.Counter.toObject(includeInstance, f), - tree: (f = msg.getTree()) && proto.yorkie.v1.JSONElement.Tree.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement} - */ -proto.yorkie.v1.JSONElement.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement; - return proto.yorkie.v1.JSONElement.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement} - */ -proto.yorkie.v1.JSONElement.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.JSONElement.JSONObject; - reader.readMessage(value,proto.yorkie.v1.JSONElement.JSONObject.deserializeBinaryFromReader); - msg.setJsonObject(value); - break; - case 2: - var value = new proto.yorkie.v1.JSONElement.JSONArray; - reader.readMessage(value,proto.yorkie.v1.JSONElement.JSONArray.deserializeBinaryFromReader); - msg.setJsonArray(value); - break; - case 3: - var value = new proto.yorkie.v1.JSONElement.Primitive; - reader.readMessage(value,proto.yorkie.v1.JSONElement.Primitive.deserializeBinaryFromReader); - msg.setPrimitive(value); - break; - case 5: - var value = new proto.yorkie.v1.JSONElement.Text; - reader.readMessage(value,proto.yorkie.v1.JSONElement.Text.deserializeBinaryFromReader); - msg.setText(value); - break; - case 6: - var value = new proto.yorkie.v1.JSONElement.Counter; - reader.readMessage(value,proto.yorkie.v1.JSONElement.Counter.deserializeBinaryFromReader); - msg.setCounter(value); - break; - case 7: - var value = new proto.yorkie.v1.JSONElement.Tree; - reader.readMessage(value,proto.yorkie.v1.JSONElement.Tree.deserializeBinaryFromReader); - msg.setTree(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getJsonObject(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.JSONElement.JSONObject.serializeBinaryToWriter - ); - } - f = message.getJsonArray(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.JSONElement.JSONArray.serializeBinaryToWriter - ); - } - f = message.getPrimitive(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.JSONElement.Primitive.serializeBinaryToWriter - ); - } - f = message.getText(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.JSONElement.Text.serializeBinaryToWriter - ); - } - f = message.getCounter(); - if (f != null) { - writer.writeMessage( - 6, - f, - proto.yorkie.v1.JSONElement.Counter.serializeBinaryToWriter - ); - } - f = message.getTree(); - if (f != null) { - writer.writeMessage( - 7, - f, - proto.yorkie.v1.JSONElement.Tree.serializeBinaryToWriter - ); - } -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.JSONElement.JSONObject.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.JSONObject.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement.JSONObject} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.JSONObject.toObject = function(includeInstance, msg) { - var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.yorkie.v1.RHTNode.toObject, includeInstance), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement.JSONObject} - */ -proto.yorkie.v1.JSONElement.JSONObject.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement.JSONObject; - return proto.yorkie.v1.JSONElement.JSONObject.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement.JSONObject} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement.JSONObject} - */ -proto.yorkie.v1.JSONElement.JSONObject.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.RHTNode; - reader.readMessage(value,proto.yorkie.v1.RHTNode.deserializeBinaryFromReader); - msg.addNodes(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.JSONObject.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement.JSONObject} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.JSONObject.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 1, - f, - proto.yorkie.v1.RHTNode.serializeBinaryToWriter - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * repeated RHTNode nodes = 1; - * @return {!Array} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.RHTNode, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this -*/ -proto.yorkie.v1.JSONElement.JSONObject.prototype.setNodesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); -}; - - -/** - * @param {!proto.yorkie.v1.RHTNode=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.RHTNode} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.yorkie.v1.RHTNode, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.clearNodesList = function() { - return this.setNodesList([]); -}; - - -/** - * optional TimeTicket created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this -*/ -proto.yorkie.v1.JSONElement.JSONObject.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket moved_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this -*/ -proto.yorkie.v1.JSONElement.JSONObject.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket removed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this -*/ -proto.yorkie.v1.JSONElement.JSONObject.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.JSONObject} returns this - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.JSONObject.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.JSONElement.JSONArray.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.JSONArray.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement.JSONArray} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.JSONArray.toObject = function(includeInstance, msg) { - var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.yorkie.v1.RGANode.toObject, includeInstance), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement.JSONArray} - */ -proto.yorkie.v1.JSONElement.JSONArray.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement.JSONArray; - return proto.yorkie.v1.JSONElement.JSONArray.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement.JSONArray} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement.JSONArray} - */ -proto.yorkie.v1.JSONElement.JSONArray.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.RGANode; - reader.readMessage(value,proto.yorkie.v1.RGANode.deserializeBinaryFromReader); - msg.addNodes(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.JSONArray.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement.JSONArray} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.JSONArray.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 1, - f, - proto.yorkie.v1.RGANode.serializeBinaryToWriter - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * repeated RGANode nodes = 1; - * @return {!Array} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.RGANode, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this -*/ -proto.yorkie.v1.JSONElement.JSONArray.prototype.setNodesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); -}; - - -/** - * @param {!proto.yorkie.v1.RGANode=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.RGANode} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.yorkie.v1.RGANode, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.clearNodesList = function() { - return this.setNodesList([]); -}; - - -/** - * optional TimeTicket created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this -*/ -proto.yorkie.v1.JSONElement.JSONArray.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket moved_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this -*/ -proto.yorkie.v1.JSONElement.JSONArray.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket removed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this -*/ -proto.yorkie.v1.JSONElement.JSONArray.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.JSONArray} returns this - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.JSONArray.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.Primitive.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement.Primitive} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Primitive.toObject = function(includeInstance, msg) { - var f, obj = { - type: jspb.Message.getFieldWithDefault(msg, 1, 0), - value: msg.getValue_asB64(), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement.Primitive} - */ -proto.yorkie.v1.JSONElement.Primitive.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement.Primitive; - return proto.yorkie.v1.JSONElement.Primitive.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement.Primitive} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement.Primitive} - */ -proto.yorkie.v1.JSONElement.Primitive.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {!proto.yorkie.v1.ValueType} */ (reader.readEnum()); - msg.setType(value); - break; - case 2: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setValue(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 5: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.Primitive.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement.Primitive} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Primitive.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 1, - f - ); - } - f = message.getValue_asU8(); - if (f.length > 0) { - writer.writeBytes( - 2, - f - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional ValueType type = 1; - * @return {!proto.yorkie.v1.ValueType} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getType = function() { - return /** @type {!proto.yorkie.v1.ValueType} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); -}; - - -/** - * @param {!proto.yorkie.v1.ValueType} value - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 1, value); -}; - - -/** - * optional bytes value = 2; - * @return {string} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * optional bytes value = 2; - * This is a type-conversion wrapper around `getValue()` - * @return {string} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getValue_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getValue())); -}; - - -/** - * optional bytes value = 2; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getValue()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getValue_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getValue())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.setValue = function(value) { - return jspb.Message.setProto3BytesField(this, 2, value); -}; - - -/** - * optional TimeTicket created_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this -*/ -proto.yorkie.v1.JSONElement.Primitive.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket moved_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this -*/ -proto.yorkie.v1.JSONElement.Primitive.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * optional TimeTicket removed_at = 5; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this -*/ -proto.yorkie.v1.JSONElement.Primitive.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Primitive} returns this - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Primitive.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 5) != null; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.JSONElement.Text.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.Text.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.Text.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement.Text} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Text.toObject = function(includeInstance, msg) { - var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.yorkie.v1.TextNode.toObject, includeInstance), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement.Text} - */ -proto.yorkie.v1.JSONElement.Text.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement.Text; - return proto.yorkie.v1.JSONElement.Text.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement.Text} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement.Text} - */ -proto.yorkie.v1.JSONElement.Text.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TextNode; - reader.readMessage(value,proto.yorkie.v1.TextNode.deserializeBinaryFromReader); - msg.addNodes(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.Text.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.Text.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement.Text} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Text.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 1, - f, - proto.yorkie.v1.TextNode.serializeBinaryToWriter - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * repeated TextNode nodes = 1; - * @return {!Array} - */ -proto.yorkie.v1.JSONElement.Text.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.TextNode, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.JSONElement.Text} returns this -*/ -proto.yorkie.v1.JSONElement.Text.prototype.setNodesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); -}; - - -/** - * @param {!proto.yorkie.v1.TextNode=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.TextNode} - */ -proto.yorkie.v1.JSONElement.Text.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.yorkie.v1.TextNode, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.JSONElement.Text} returns this - */ -proto.yorkie.v1.JSONElement.Text.prototype.clearNodesList = function() { - return this.setNodesList([]); -}; - - -/** - * optional TimeTicket created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Text.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Text} returns this -*/ -proto.yorkie.v1.JSONElement.Text.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Text} returns this - */ -proto.yorkie.v1.JSONElement.Text.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Text.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket moved_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Text.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Text} returns this -*/ -proto.yorkie.v1.JSONElement.Text.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Text} returns this - */ -proto.yorkie.v1.JSONElement.Text.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Text.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket removed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Text.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Text} returns this -*/ -proto.yorkie.v1.JSONElement.Text.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Text} returns this - */ -proto.yorkie.v1.JSONElement.Text.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Text.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.Counter.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement.Counter} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Counter.toObject = function(includeInstance, msg) { - var f, obj = { - type: jspb.Message.getFieldWithDefault(msg, 1, 0), - value: msg.getValue_asB64(), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement.Counter} - */ -proto.yorkie.v1.JSONElement.Counter.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement.Counter; - return proto.yorkie.v1.JSONElement.Counter.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement.Counter} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement.Counter} - */ -proto.yorkie.v1.JSONElement.Counter.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {!proto.yorkie.v1.ValueType} */ (reader.readEnum()); - msg.setType(value); - break; - case 2: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setValue(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 5: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.Counter.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement.Counter} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Counter.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 1, - f - ); - } - f = message.getValue_asU8(); - if (f.length > 0) { - writer.writeBytes( - 2, - f - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional ValueType type = 1; - * @return {!proto.yorkie.v1.ValueType} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getType = function() { - return /** @type {!proto.yorkie.v1.ValueType} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); -}; - - -/** - * @param {!proto.yorkie.v1.ValueType} value - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this - */ -proto.yorkie.v1.JSONElement.Counter.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 1, value); -}; - - -/** - * optional bytes value = 2; - * @return {string} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * optional bytes value = 2; - * This is a type-conversion wrapper around `getValue()` - * @return {string} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getValue_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getValue())); -}; - - -/** - * optional bytes value = 2; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getValue()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getValue_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getValue())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this - */ -proto.yorkie.v1.JSONElement.Counter.prototype.setValue = function(value) { - return jspb.Message.setProto3BytesField(this, 2, value); -}; - - -/** - * optional TimeTicket created_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this -*/ -proto.yorkie.v1.JSONElement.Counter.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this - */ -proto.yorkie.v1.JSONElement.Counter.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket moved_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this -*/ -proto.yorkie.v1.JSONElement.Counter.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this - */ -proto.yorkie.v1.JSONElement.Counter.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * optional TimeTicket removed_at = 5; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this -*/ -proto.yorkie.v1.JSONElement.Counter.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Counter} returns this - */ -proto.yorkie.v1.JSONElement.Counter.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Counter.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 5) != null; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.JSONElement.Tree.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.JSONElement.Tree.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.JSONElement.Tree} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Tree.toObject = function(includeInstance, msg) { - var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.yorkie.v1.TreeNode.toObject, includeInstance), - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - movedAt: (f = msg.getMovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.JSONElement.Tree} - */ -proto.yorkie.v1.JSONElement.Tree.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.JSONElement.Tree; - return proto.yorkie.v1.JSONElement.Tree.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.JSONElement.Tree} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.JSONElement.Tree} - */ -proto.yorkie.v1.JSONElement.Tree.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TreeNode; - reader.readMessage(value,proto.yorkie.v1.TreeNode.deserializeBinaryFromReader); - msg.addNodes(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setMovedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.JSONElement.Tree.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.JSONElement.Tree} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.JSONElement.Tree.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 1, - f, - proto.yorkie.v1.TreeNode.serializeBinaryToWriter - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getMovedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * repeated TreeNode nodes = 1; - * @return {!Array} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.TreeNode, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this -*/ -proto.yorkie.v1.JSONElement.Tree.prototype.setNodesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); -}; - - -/** - * @param {!proto.yorkie.v1.TreeNode=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.TreeNode} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.yorkie.v1.TreeNode, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this - */ -proto.yorkie.v1.JSONElement.Tree.prototype.clearNodesList = function() { - return this.setNodesList([]); -}; - - -/** - * optional TimeTicket created_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this -*/ -proto.yorkie.v1.JSONElement.Tree.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this - */ -proto.yorkie.v1.JSONElement.Tree.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional TimeTicket moved_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.getMovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this -*/ -proto.yorkie.v1.JSONElement.Tree.prototype.setMovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this - */ -proto.yorkie.v1.JSONElement.Tree.prototype.clearMovedAt = function() { - return this.setMovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.hasMovedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TimeTicket removed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this -*/ -proto.yorkie.v1.JSONElement.Tree.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement.Tree} returns this - */ -proto.yorkie.v1.JSONElement.Tree.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.Tree.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * optional JSONObject json_object = 1; - * @return {?proto.yorkie.v1.JSONElement.JSONObject} - */ -proto.yorkie.v1.JSONElement.prototype.getJsonObject = function() { - return /** @type{?proto.yorkie.v1.JSONElement.JSONObject} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement.JSONObject, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement.JSONObject|undefined} value - * @return {!proto.yorkie.v1.JSONElement} returns this -*/ -proto.yorkie.v1.JSONElement.prototype.setJsonObject = function(value) { - return jspb.Message.setOneofWrapperField(this, 1, proto.yorkie.v1.JSONElement.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement} returns this - */ -proto.yorkie.v1.JSONElement.prototype.clearJsonObject = function() { - return this.setJsonObject(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.prototype.hasJsonObject = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional JSONArray json_array = 2; - * @return {?proto.yorkie.v1.JSONElement.JSONArray} - */ -proto.yorkie.v1.JSONElement.prototype.getJsonArray = function() { - return /** @type{?proto.yorkie.v1.JSONElement.JSONArray} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement.JSONArray, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement.JSONArray|undefined} value - * @return {!proto.yorkie.v1.JSONElement} returns this -*/ -proto.yorkie.v1.JSONElement.prototype.setJsonArray = function(value) { - return jspb.Message.setOneofWrapperField(this, 2, proto.yorkie.v1.JSONElement.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement} returns this - */ -proto.yorkie.v1.JSONElement.prototype.clearJsonArray = function() { - return this.setJsonArray(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.prototype.hasJsonArray = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional Primitive primitive = 3; - * @return {?proto.yorkie.v1.JSONElement.Primitive} - */ -proto.yorkie.v1.JSONElement.prototype.getPrimitive = function() { - return /** @type{?proto.yorkie.v1.JSONElement.Primitive} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement.Primitive, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement.Primitive|undefined} value - * @return {!proto.yorkie.v1.JSONElement} returns this -*/ -proto.yorkie.v1.JSONElement.prototype.setPrimitive = function(value) { - return jspb.Message.setOneofWrapperField(this, 3, proto.yorkie.v1.JSONElement.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement} returns this - */ -proto.yorkie.v1.JSONElement.prototype.clearPrimitive = function() { - return this.setPrimitive(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.prototype.hasPrimitive = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional Text text = 5; - * @return {?proto.yorkie.v1.JSONElement.Text} - */ -proto.yorkie.v1.JSONElement.prototype.getText = function() { - return /** @type{?proto.yorkie.v1.JSONElement.Text} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement.Text, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement.Text|undefined} value - * @return {!proto.yorkie.v1.JSONElement} returns this -*/ -proto.yorkie.v1.JSONElement.prototype.setText = function(value) { - return jspb.Message.setOneofWrapperField(this, 5, proto.yorkie.v1.JSONElement.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement} returns this - */ -proto.yorkie.v1.JSONElement.prototype.clearText = function() { - return this.setText(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.prototype.hasText = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * optional Counter counter = 6; - * @return {?proto.yorkie.v1.JSONElement.Counter} - */ -proto.yorkie.v1.JSONElement.prototype.getCounter = function() { - return /** @type{?proto.yorkie.v1.JSONElement.Counter} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement.Counter, 6)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement.Counter|undefined} value - * @return {!proto.yorkie.v1.JSONElement} returns this -*/ -proto.yorkie.v1.JSONElement.prototype.setCounter = function(value) { - return jspb.Message.setOneofWrapperField(this, 6, proto.yorkie.v1.JSONElement.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement} returns this - */ -proto.yorkie.v1.JSONElement.prototype.clearCounter = function() { - return this.setCounter(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.prototype.hasCounter = function() { - return jspb.Message.getField(this, 6) != null; -}; - - -/** - * optional Tree tree = 7; - * @return {?proto.yorkie.v1.JSONElement.Tree} - */ -proto.yorkie.v1.JSONElement.prototype.getTree = function() { - return /** @type{?proto.yorkie.v1.JSONElement.Tree} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement.Tree, 7)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement.Tree|undefined} value - * @return {!proto.yorkie.v1.JSONElement} returns this -*/ -proto.yorkie.v1.JSONElement.prototype.setTree = function(value) { - return jspb.Message.setOneofWrapperField(this, 7, proto.yorkie.v1.JSONElement.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.JSONElement} returns this - */ -proto.yorkie.v1.JSONElement.prototype.clearTree = function() { - return this.setTree(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.JSONElement.prototype.hasTree = function() { - return jspb.Message.getField(this, 7) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.RHTNode.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.RHTNode.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.RHTNode} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RHTNode.toObject = function(includeInstance, msg) { - var f, obj = { - key: jspb.Message.getFieldWithDefault(msg, 1, ""), - element: (f = msg.getElement()) && proto.yorkie.v1.JSONElement.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.RHTNode} - */ -proto.yorkie.v1.RHTNode.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.RHTNode; - return proto.yorkie.v1.RHTNode.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.RHTNode} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.RHTNode} - */ -proto.yorkie.v1.RHTNode.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setKey(value); - break; - case 2: - var value = new proto.yorkie.v1.JSONElement; - reader.readMessage(value,proto.yorkie.v1.JSONElement.deserializeBinaryFromReader); - msg.setElement(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.RHTNode.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.RHTNode.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.RHTNode} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RHTNode.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getKey(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getElement(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.JSONElement.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string key = 1; - * @return {string} - */ -proto.yorkie.v1.RHTNode.prototype.getKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.RHTNode} returns this - */ -proto.yorkie.v1.RHTNode.prototype.setKey = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional JSONElement element = 2; - * @return {?proto.yorkie.v1.JSONElement} - */ -proto.yorkie.v1.RHTNode.prototype.getElement = function() { - return /** @type{?proto.yorkie.v1.JSONElement} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement|undefined} value - * @return {!proto.yorkie.v1.RHTNode} returns this -*/ -proto.yorkie.v1.RHTNode.prototype.setElement = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.RHTNode} returns this - */ -proto.yorkie.v1.RHTNode.prototype.clearElement = function() { - return this.setElement(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.RHTNode.prototype.hasElement = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.RGANode.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.RGANode.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.RGANode} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RGANode.toObject = function(includeInstance, msg) { - var f, obj = { - next: (f = msg.getNext()) && proto.yorkie.v1.RGANode.toObject(includeInstance, f), - element: (f = msg.getElement()) && proto.yorkie.v1.JSONElement.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.RGANode} - */ -proto.yorkie.v1.RGANode.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.RGANode; - return proto.yorkie.v1.RGANode.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.RGANode} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.RGANode} - */ -proto.yorkie.v1.RGANode.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.RGANode; - reader.readMessage(value,proto.yorkie.v1.RGANode.deserializeBinaryFromReader); - msg.setNext(value); - break; - case 2: - var value = new proto.yorkie.v1.JSONElement; - reader.readMessage(value,proto.yorkie.v1.JSONElement.deserializeBinaryFromReader); - msg.setElement(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.RGANode.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.RGANode.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.RGANode} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RGANode.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getNext(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.RGANode.serializeBinaryToWriter - ); - } - f = message.getElement(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.JSONElement.serializeBinaryToWriter - ); - } -}; - - -/** - * optional RGANode next = 1; - * @return {?proto.yorkie.v1.RGANode} - */ -proto.yorkie.v1.RGANode.prototype.getNext = function() { - return /** @type{?proto.yorkie.v1.RGANode} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.RGANode, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.RGANode|undefined} value - * @return {!proto.yorkie.v1.RGANode} returns this -*/ -proto.yorkie.v1.RGANode.prototype.setNext = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.RGANode} returns this - */ -proto.yorkie.v1.RGANode.prototype.clearNext = function() { - return this.setNext(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.RGANode.prototype.hasNext = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional JSONElement element = 2; - * @return {?proto.yorkie.v1.JSONElement} - */ -proto.yorkie.v1.RGANode.prototype.getElement = function() { - return /** @type{?proto.yorkie.v1.JSONElement} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.JSONElement, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.JSONElement|undefined} value - * @return {!proto.yorkie.v1.RGANode} returns this -*/ -proto.yorkie.v1.RGANode.prototype.setElement = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.RGANode} returns this - */ -proto.yorkie.v1.RGANode.prototype.clearElement = function() { - return this.setElement(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.RGANode.prototype.hasElement = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.NodeAttr.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.NodeAttr.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.NodeAttr} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.NodeAttr.toObject = function(includeInstance, msg) { - var f, obj = { - value: jspb.Message.getFieldWithDefault(msg, 1, ""), - updatedAt: (f = msg.getUpdatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.NodeAttr} - */ -proto.yorkie.v1.NodeAttr.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.NodeAttr; - return proto.yorkie.v1.NodeAttr.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.NodeAttr} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.NodeAttr} - */ -proto.yorkie.v1.NodeAttr.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setValue(value); - break; - case 2: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setUpdatedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.NodeAttr.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.NodeAttr.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.NodeAttr} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.NodeAttr.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getValue(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getUpdatedAt(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string value = 1; - * @return {string} - */ -proto.yorkie.v1.NodeAttr.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.NodeAttr} returns this - */ -proto.yorkie.v1.NodeAttr.prototype.setValue = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional TimeTicket updated_at = 2; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.NodeAttr.prototype.getUpdatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.NodeAttr} returns this -*/ -proto.yorkie.v1.NodeAttr.prototype.setUpdatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.NodeAttr} returns this - */ -proto.yorkie.v1.NodeAttr.prototype.clearUpdatedAt = function() { - return this.setUpdatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.NodeAttr.prototype.hasUpdatedAt = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TextNode.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TextNode.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TextNode} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TextNode.toObject = function(includeInstance, msg) { - var f, obj = { - id: (f = msg.getId()) && proto.yorkie.v1.TextNodeID.toObject(includeInstance, f), - value: jspb.Message.getFieldWithDefault(msg, 2, ""), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - insPrevId: (f = msg.getInsPrevId()) && proto.yorkie.v1.TextNodeID.toObject(includeInstance, f), - attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, proto.yorkie.v1.NodeAttr.toObject) : [] - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TextNode} - */ -proto.yorkie.v1.TextNode.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TextNode; - return proto.yorkie.v1.TextNode.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TextNode} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TextNode} - */ -proto.yorkie.v1.TextNode.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TextNodeID; - reader.readMessage(value,proto.yorkie.v1.TextNodeID.deserializeBinaryFromReader); - msg.setId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setValue(value); - break; - case 3: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - case 4: - var value = new proto.yorkie.v1.TextNodeID; - reader.readMessage(value,proto.yorkie.v1.TextNodeID.deserializeBinaryFromReader); - msg.setInsPrevId(value); - break; - case 5: - var value = msg.getAttributesMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.NodeAttr.deserializeBinaryFromReader, "", new proto.yorkie.v1.NodeAttr()); - }); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TextNode.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TextNode.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TextNode} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TextNode.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getId(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TextNodeID.serializeBinaryToWriter - ); - } - f = message.getValue(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getInsPrevId(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TextNodeID.serializeBinaryToWriter - ); - } - f = message.getAttributesMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(5, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.NodeAttr.serializeBinaryToWriter); - } -}; - - -/** - * optional TextNodeID id = 1; - * @return {?proto.yorkie.v1.TextNodeID} - */ -proto.yorkie.v1.TextNode.prototype.getId = function() { - return /** @type{?proto.yorkie.v1.TextNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodeID, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodeID|undefined} value - * @return {!proto.yorkie.v1.TextNode} returns this -*/ -proto.yorkie.v1.TextNode.prototype.setId = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TextNode} returns this - */ -proto.yorkie.v1.TextNode.prototype.clearId = function() { - return this.setId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TextNode.prototype.hasId = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional string value = 2; - * @return {string} - */ -proto.yorkie.v1.TextNode.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.TextNode} returns this - */ -proto.yorkie.v1.TextNode.prototype.setValue = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional TimeTicket removed_at = 3; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TextNode.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.TextNode} returns this -*/ -proto.yorkie.v1.TextNode.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TextNode} returns this - */ -proto.yorkie.v1.TextNode.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TextNode.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional TextNodeID ins_prev_id = 4; - * @return {?proto.yorkie.v1.TextNodeID} - */ -proto.yorkie.v1.TextNode.prototype.getInsPrevId = function() { - return /** @type{?proto.yorkie.v1.TextNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TextNodeID, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TextNodeID|undefined} value - * @return {!proto.yorkie.v1.TextNode} returns this -*/ -proto.yorkie.v1.TextNode.prototype.setInsPrevId = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TextNode} returns this - */ -proto.yorkie.v1.TextNode.prototype.clearInsPrevId = function() { - return this.setInsPrevId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TextNode.prototype.hasInsPrevId = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * map attributes = 5; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.TextNode.prototype.getAttributesMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 5, opt_noLazyCreate, - proto.yorkie.v1.NodeAttr)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.TextNode} returns this - */ -proto.yorkie.v1.TextNode.prototype.clearAttributesMap = function() { - this.getAttributesMap().clear(); - return this; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TextNodeID.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TextNodeID.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TextNodeID} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TextNodeID.toObject = function(includeInstance, msg) { - var f, obj = { - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - offset: jspb.Message.getFieldWithDefault(msg, 2, 0) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TextNodeID} - */ -proto.yorkie.v1.TextNodeID.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TextNodeID; - return proto.yorkie.v1.TextNodeID.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TextNodeID} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TextNodeID} - */ -proto.yorkie.v1.TextNodeID.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt32()); - msg.setOffset(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TextNodeID.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TextNodeID.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TextNodeID} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TextNodeID.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getOffset(); - if (f !== 0) { - writer.writeInt32( - 2, - f - ); - } -}; - - -/** - * optional TimeTicket created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TextNodeID.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.TextNodeID} returns this -*/ -proto.yorkie.v1.TextNodeID.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TextNodeID} returns this - */ -proto.yorkie.v1.TextNodeID.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TextNodeID.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional int32 offset = 2; - * @return {number} - */ -proto.yorkie.v1.TextNodeID.prototype.getOffset = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.TextNodeID} returns this - */ -proto.yorkie.v1.TextNodeID.prototype.setOffset = function(value) { - return jspb.Message.setProto3IntField(this, 2, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TreeNode.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TreeNode.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TreeNode} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreeNode.toObject = function(includeInstance, msg) { - var f, obj = { - id: (f = msg.getId()) && proto.yorkie.v1.TreeNodeID.toObject(includeInstance, f), - type: jspb.Message.getFieldWithDefault(msg, 2, ""), - value: jspb.Message.getFieldWithDefault(msg, 3, ""), - removedAt: (f = msg.getRemovedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - insPrevId: (f = msg.getInsPrevId()) && proto.yorkie.v1.TreeNodeID.toObject(includeInstance, f), - insNextId: (f = msg.getInsNextId()) && proto.yorkie.v1.TreeNodeID.toObject(includeInstance, f), - depth: jspb.Message.getFieldWithDefault(msg, 7, 0), - attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, proto.yorkie.v1.NodeAttr.toObject) : [] - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TreeNode} - */ -proto.yorkie.v1.TreeNode.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TreeNode; - return proto.yorkie.v1.TreeNode.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TreeNode} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TreeNode} - */ -proto.yorkie.v1.TreeNode.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TreeNodeID; - reader.readMessage(value,proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader); - msg.setId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setType(value); - break; - case 3: - var value = /** @type {string} */ (reader.readString()); - msg.setValue(value); - break; - case 4: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); - break; - case 5: - var value = new proto.yorkie.v1.TreeNodeID; - reader.readMessage(value,proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader); - msg.setInsPrevId(value); - break; - case 6: - var value = new proto.yorkie.v1.TreeNodeID; - reader.readMessage(value,proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader); - msg.setInsNextId(value); - break; - case 7: - var value = /** @type {number} */ (reader.readInt32()); - msg.setDepth(value); - break; - case 8: - var value = msg.getAttributesMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.yorkie.v1.NodeAttr.deserializeBinaryFromReader, "", new proto.yorkie.v1.NodeAttr()); - }); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TreeNode.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TreeNode.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TreeNode} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreeNode.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getId(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter - ); - } - f = message.getType(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getValue(); - if (f.length > 0) { - writer.writeString( - 3, - f - ); - } - f = message.getRemovedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getInsPrevId(); - if (f != null) { - writer.writeMessage( - 5, - f, - proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter - ); - } - f = message.getInsNextId(); - if (f != null) { - writer.writeMessage( - 6, - f, - proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter - ); - } - f = message.getDepth(); - if (f !== 0) { - writer.writeInt32( - 7, - f - ); - } - f = message.getAttributesMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(8, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.yorkie.v1.NodeAttr.serializeBinaryToWriter); - } -}; - - -/** - * optional TreeNodeID id = 1; - * @return {?proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreeNode.prototype.getId = function() { - return /** @type{?proto.yorkie.v1.TreeNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreeNodeID, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TreeNodeID|undefined} value - * @return {!proto.yorkie.v1.TreeNode} returns this -*/ -proto.yorkie.v1.TreeNode.prototype.setId = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.clearId = function() { - return this.setId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreeNode.prototype.hasId = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional string type = 2; - * @return {string} - */ -proto.yorkie.v1.TreeNode.prototype.getType = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.setType = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional string value = 3; - * @return {string} - */ -proto.yorkie.v1.TreeNode.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.setValue = function(value) { - return jspb.Message.setProto3StringField(this, 3, value); -}; - - -/** - * optional TimeTicket removed_at = 4; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TreeNode.prototype.getRemovedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 4)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.TreeNode} returns this -*/ -proto.yorkie.v1.TreeNode.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreeNode.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * optional TreeNodeID ins_prev_id = 5; - * @return {?proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreeNode.prototype.getInsPrevId = function() { - return /** @type{?proto.yorkie.v1.TreeNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreeNodeID, 5)); -}; - - -/** - * @param {?proto.yorkie.v1.TreeNodeID|undefined} value - * @return {!proto.yorkie.v1.TreeNode} returns this -*/ -proto.yorkie.v1.TreeNode.prototype.setInsPrevId = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.clearInsPrevId = function() { - return this.setInsPrevId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreeNode.prototype.hasInsPrevId = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * optional TreeNodeID ins_next_id = 6; - * @return {?proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreeNode.prototype.getInsNextId = function() { - return /** @type{?proto.yorkie.v1.TreeNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreeNodeID, 6)); -}; - - -/** - * @param {?proto.yorkie.v1.TreeNodeID|undefined} value - * @return {!proto.yorkie.v1.TreeNode} returns this -*/ -proto.yorkie.v1.TreeNode.prototype.setInsNextId = function(value) { - return jspb.Message.setWrapperField(this, 6, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.clearInsNextId = function() { - return this.setInsNextId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreeNode.prototype.hasInsNextId = function() { - return jspb.Message.getField(this, 6) != null; -}; - - -/** - * optional int32 depth = 7; - * @return {number} - */ -proto.yorkie.v1.TreeNode.prototype.getDepth = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 7, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.setDepth = function(value) { - return jspb.Message.setProto3IntField(this, 7, value); -}; - - -/** - * map attributes = 8; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.TreeNode.prototype.getAttributesMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 8, opt_noLazyCreate, - proto.yorkie.v1.NodeAttr)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.TreeNode} returns this - */ -proto.yorkie.v1.TreeNode.prototype.clearAttributesMap = function() { - this.getAttributesMap().clear(); - return this; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.TreeNodes.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TreeNodes.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TreeNodes.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TreeNodes} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreeNodes.toObject = function(includeInstance, msg) { - var f, obj = { - contentList: jspb.Message.toObjectList(msg.getContentList(), - proto.yorkie.v1.TreeNode.toObject, includeInstance) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TreeNodes} - */ -proto.yorkie.v1.TreeNodes.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TreeNodes; - return proto.yorkie.v1.TreeNodes.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TreeNodes} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TreeNodes} - */ -proto.yorkie.v1.TreeNodes.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TreeNode; - reader.readMessage(value,proto.yorkie.v1.TreeNode.deserializeBinaryFromReader); - msg.addContent(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TreeNodes.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TreeNodes.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TreeNodes} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreeNodes.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getContentList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 1, - f, - proto.yorkie.v1.TreeNode.serializeBinaryToWriter - ); - } -}; - - -/** - * repeated TreeNode content = 1; - * @return {!Array} - */ -proto.yorkie.v1.TreeNodes.prototype.getContentList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.yorkie.v1.TreeNode, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.TreeNodes} returns this -*/ -proto.yorkie.v1.TreeNodes.prototype.setContentList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); -}; - - -/** - * @param {!proto.yorkie.v1.TreeNode=} opt_value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.TreeNode} - */ -proto.yorkie.v1.TreeNodes.prototype.addContent = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.yorkie.v1.TreeNode, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.TreeNodes} returns this - */ -proto.yorkie.v1.TreeNodes.prototype.clearContentList = function() { - return this.setContentList([]); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TreeNodeID.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TreeNodeID.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TreeNodeID} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreeNodeID.toObject = function(includeInstance, msg) { - var f, obj = { - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - offset: jspb.Message.getFieldWithDefault(msg, 2, 0) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreeNodeID.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TreeNodeID; - return proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TreeNodeID} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt32()); - msg.setOffset(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TreeNodeID.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TreeNodeID} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getOffset(); - if (f !== 0) { - writer.writeInt32( - 2, - f - ); - } -}; - - -/** - * optional TimeTicket created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TreeNodeID.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.TreeNodeID} returns this -*/ -proto.yorkie.v1.TreeNodeID.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreeNodeID} returns this - */ -proto.yorkie.v1.TreeNodeID.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreeNodeID.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional int32 offset = 2; - * @return {number} - */ -proto.yorkie.v1.TreeNodeID.prototype.getOffset = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.TreeNodeID} returns this - */ -proto.yorkie.v1.TreeNodeID.prototype.setOffset = function(value) { - return jspb.Message.setProto3IntField(this, 2, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TreePos.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TreePos.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TreePos} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreePos.toObject = function(includeInstance, msg) { - var f, obj = { - parentId: (f = msg.getParentId()) && proto.yorkie.v1.TreeNodeID.toObject(includeInstance, f), - leftSiblingId: (f = msg.getLeftSiblingId()) && proto.yorkie.v1.TreeNodeID.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TreePos} - */ -proto.yorkie.v1.TreePos.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TreePos; - return proto.yorkie.v1.TreePos.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TreePos} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TreePos} - */ -proto.yorkie.v1.TreePos.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TreeNodeID; - reader.readMessage(value,proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader); - msg.setParentId(value); - break; - case 2: - var value = new proto.yorkie.v1.TreeNodeID; - reader.readMessage(value,proto.yorkie.v1.TreeNodeID.deserializeBinaryFromReader); - msg.setLeftSiblingId(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TreePos.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TreePos.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TreePos} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TreePos.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getParentId(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter - ); - } - f = message.getLeftSiblingId(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.TreeNodeID.serializeBinaryToWriter - ); - } -}; - - -/** - * optional TreeNodeID parent_id = 1; - * @return {?proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreePos.prototype.getParentId = function() { - return /** @type{?proto.yorkie.v1.TreeNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreeNodeID, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TreeNodeID|undefined} value - * @return {!proto.yorkie.v1.TreePos} returns this -*/ -proto.yorkie.v1.TreePos.prototype.setParentId = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreePos} returns this - */ -proto.yorkie.v1.TreePos.prototype.clearParentId = function() { - return this.setParentId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreePos.prototype.hasParentId = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional TreeNodeID left_sibling_id = 2; - * @return {?proto.yorkie.v1.TreeNodeID} - */ -proto.yorkie.v1.TreePos.prototype.getLeftSiblingId = function() { - return /** @type{?proto.yorkie.v1.TreeNodeID} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TreeNodeID, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.TreeNodeID|undefined} value - * @return {!proto.yorkie.v1.TreePos} returns this -*/ -proto.yorkie.v1.TreePos.prototype.setLeftSiblingId = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TreePos} returns this - */ -proto.yorkie.v1.TreePos.prototype.clearLeftSiblingId = function() { - return this.setLeftSiblingId(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TreePos.prototype.hasLeftSiblingId = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.User.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.User.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.User} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.User.toObject = function(includeInstance, msg) { - var f, obj = { - id: jspb.Message.getFieldWithDefault(msg, 1, ""), - username: jspb.Message.getFieldWithDefault(msg, 2, ""), - createdAt: (f = msg.getCreatedAt()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.User} - */ -proto.yorkie.v1.User.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.User; - return proto.yorkie.v1.User.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.User} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.User} - */ -proto.yorkie.v1.User.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setUsername(value); - break; - case 3: - var value = new google_protobuf_timestamp_pb.Timestamp; - reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.User.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.User.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.User} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.User.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getUsername(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 3, - f, - google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string id = 1; - * @return {string} - */ -proto.yorkie.v1.User.prototype.getId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.User} returns this - */ -proto.yorkie.v1.User.prototype.setId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string username = 2; - * @return {string} - */ -proto.yorkie.v1.User.prototype.getUsername = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.User} returns this - */ -proto.yorkie.v1.User.prototype.setUsername = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional google.protobuf.Timestamp created_at = 3; - * @return {?proto.google.protobuf.Timestamp} - */ -proto.yorkie.v1.User.prototype.getCreatedAt = function() { - return /** @type{?proto.google.protobuf.Timestamp} */ ( - jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 3)); -}; - - -/** - * @param {?proto.google.protobuf.Timestamp|undefined} value - * @return {!proto.yorkie.v1.User} returns this -*/ -proto.yorkie.v1.User.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.User} returns this - */ -proto.yorkie.v1.User.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.User.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 3) != null; -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.Project.repeatedFields_ = [6]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Project.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Project.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Project} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Project.toObject = function(includeInstance, msg) { - var f, obj = { - id: jspb.Message.getFieldWithDefault(msg, 1, ""), - name: jspb.Message.getFieldWithDefault(msg, 2, ""), - publicKey: jspb.Message.getFieldWithDefault(msg, 3, ""), - secretKey: jspb.Message.getFieldWithDefault(msg, 4, ""), - authWebhookUrl: jspb.Message.getFieldWithDefault(msg, 5, ""), - authWebhookMethodsList: (f = jspb.Message.getRepeatedField(msg, 6)) == null ? undefined : f, - clientDeactivateThreshold: jspb.Message.getFieldWithDefault(msg, 7, ""), - createdAt: (f = msg.getCreatedAt()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f), - updatedAt: (f = msg.getUpdatedAt()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Project} - */ -proto.yorkie.v1.Project.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Project; - return proto.yorkie.v1.Project.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Project} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Project} - */ -proto.yorkie.v1.Project.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setName(value); - break; - case 3: - var value = /** @type {string} */ (reader.readString()); - msg.setPublicKey(value); - break; - case 4: - var value = /** @type {string} */ (reader.readString()); - msg.setSecretKey(value); - break; - case 5: - var value = /** @type {string} */ (reader.readString()); - msg.setAuthWebhookUrl(value); - break; - case 6: - var value = /** @type {string} */ (reader.readString()); - msg.addAuthWebhookMethods(value); - break; - case 7: - var value = /** @type {string} */ (reader.readString()); - msg.setClientDeactivateThreshold(value); - break; - case 8: - var value = new google_protobuf_timestamp_pb.Timestamp; - reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 9: - var value = new google_protobuf_timestamp_pb.Timestamp; - reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader); - msg.setUpdatedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Project.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Project.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Project} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Project.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getName(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getPublicKey(); - if (f.length > 0) { - writer.writeString( - 3, - f - ); - } - f = message.getSecretKey(); - if (f.length > 0) { - writer.writeString( - 4, - f - ); - } - f = message.getAuthWebhookUrl(); - if (f.length > 0) { - writer.writeString( - 5, - f - ); - } - f = message.getAuthWebhookMethodsList(); - if (f.length > 0) { - writer.writeRepeatedString( - 6, - f - ); - } - f = message.getClientDeactivateThreshold(); - if (f.length > 0) { - writer.writeString( - 7, - f - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 8, - f, - google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter - ); - } - f = message.getUpdatedAt(); - if (f != null) { - writer.writeMessage( - 9, - f, - google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string id = 1; - * @return {string} - */ -proto.yorkie.v1.Project.prototype.getId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string name = 2; - * @return {string} - */ -proto.yorkie.v1.Project.prototype.getName = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setName = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional string public_key = 3; - * @return {string} - */ -proto.yorkie.v1.Project.prototype.getPublicKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setPublicKey = function(value) { - return jspb.Message.setProto3StringField(this, 3, value); -}; - - -/** - * optional string secret_key = 4; - * @return {string} - */ -proto.yorkie.v1.Project.prototype.getSecretKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setSecretKey = function(value) { - return jspb.Message.setProto3StringField(this, 4, value); -}; - - -/** - * optional string auth_webhook_url = 5; - * @return {string} - */ -proto.yorkie.v1.Project.prototype.getAuthWebhookUrl = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setAuthWebhookUrl = function(value) { - return jspb.Message.setProto3StringField(this, 5, value); -}; - - -/** - * repeated string auth_webhook_methods = 6; - * @return {!Array} - */ -proto.yorkie.v1.Project.prototype.getAuthWebhookMethodsList = function() { - return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 6)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setAuthWebhookMethodsList = function(value) { - return jspb.Message.setField(this, 6, value || []); -}; - - -/** - * @param {string} value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.addAuthWebhookMethods = function(value, opt_index) { - return jspb.Message.addToRepeatedField(this, 6, value, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.clearAuthWebhookMethodsList = function() { - return this.setAuthWebhookMethodsList([]); -}; - - -/** - * optional string client_deactivate_threshold = 7; - * @return {string} - */ -proto.yorkie.v1.Project.prototype.getClientDeactivateThreshold = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.setClientDeactivateThreshold = function(value) { - return jspb.Message.setProto3StringField(this, 7, value); -}; - - -/** - * optional google.protobuf.Timestamp created_at = 8; - * @return {?proto.google.protobuf.Timestamp} - */ -proto.yorkie.v1.Project.prototype.getCreatedAt = function() { - return /** @type{?proto.google.protobuf.Timestamp} */ ( - jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 8)); -}; - - -/** - * @param {?proto.google.protobuf.Timestamp|undefined} value - * @return {!proto.yorkie.v1.Project} returns this -*/ -proto.yorkie.v1.Project.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 8, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Project.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 8) != null; -}; - - -/** - * optional google.protobuf.Timestamp updated_at = 9; - * @return {?proto.google.protobuf.Timestamp} - */ -proto.yorkie.v1.Project.prototype.getUpdatedAt = function() { - return /** @type{?proto.google.protobuf.Timestamp} */ ( - jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 9)); -}; - - -/** - * @param {?proto.google.protobuf.Timestamp|undefined} value - * @return {!proto.yorkie.v1.Project} returns this -*/ -proto.yorkie.v1.Project.prototype.setUpdatedAt = function(value) { - return jspb.Message.setWrapperField(this, 9, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.Project} returns this - */ -proto.yorkie.v1.Project.prototype.clearUpdatedAt = function() { - return this.setUpdatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.Project.prototype.hasUpdatedAt = function() { - return jspb.Message.getField(this, 9) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.UpdatableProjectFields.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.UpdatableProjectFields} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.UpdatableProjectFields.toObject = function(includeInstance, msg) { - var f, obj = { - name: (f = msg.getName()) && google_protobuf_wrappers_pb.StringValue.toObject(includeInstance, f), - authWebhookUrl: (f = msg.getAuthWebhookUrl()) && google_protobuf_wrappers_pb.StringValue.toObject(includeInstance, f), - authWebhookMethods: (f = msg.getAuthWebhookMethods()) && proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.toObject(includeInstance, f), - clientDeactivateThreshold: (f = msg.getClientDeactivateThreshold()) && google_protobuf_wrappers_pb.StringValue.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.UpdatableProjectFields} - */ -proto.yorkie.v1.UpdatableProjectFields.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.UpdatableProjectFields; - return proto.yorkie.v1.UpdatableProjectFields.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.UpdatableProjectFields} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.UpdatableProjectFields} - */ -proto.yorkie.v1.UpdatableProjectFields.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new google_protobuf_wrappers_pb.StringValue; - reader.readMessage(value,google_protobuf_wrappers_pb.StringValue.deserializeBinaryFromReader); - msg.setName(value); - break; - case 2: - var value = new google_protobuf_wrappers_pb.StringValue; - reader.readMessage(value,google_protobuf_wrappers_pb.StringValue.deserializeBinaryFromReader); - msg.setAuthWebhookUrl(value); - break; - case 3: - var value = new proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods; - reader.readMessage(value,proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.deserializeBinaryFromReader); - msg.setAuthWebhookMethods(value); - break; - case 4: - var value = new google_protobuf_wrappers_pb.StringValue; - reader.readMessage(value,google_protobuf_wrappers_pb.StringValue.deserializeBinaryFromReader); - msg.setClientDeactivateThreshold(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.UpdatableProjectFields.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.UpdatableProjectFields} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.UpdatableProjectFields.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getName(); - if (f != null) { - writer.writeMessage( - 1, - f, - google_protobuf_wrappers_pb.StringValue.serializeBinaryToWriter - ); - } - f = message.getAuthWebhookUrl(); - if (f != null) { - writer.writeMessage( - 2, - f, - google_protobuf_wrappers_pb.StringValue.serializeBinaryToWriter - ); - } - f = message.getAuthWebhookMethods(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.serializeBinaryToWriter - ); - } - f = message.getClientDeactivateThreshold(); - if (f != null) { - writer.writeMessage( - 4, - f, - google_protobuf_wrappers_pb.StringValue.serializeBinaryToWriter - ); - } -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.toObject = function(includeInstance, msg) { - var f, obj = { - methodsList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods; - return proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.addMethods(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getMethodsList(); - if (f.length > 0) { - writer.writeRepeatedString( - 1, - f - ); - } -}; - - -/** - * repeated string methods = 1; - * @return {!Array} - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.prototype.getMethodsList = function() { - return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.prototype.setMethodsList = function(value) { - return jspb.Message.setField(this, 1, value || []); -}; - - -/** - * @param {string} value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.prototype.addMethods = function(value, opt_index) { - return jspb.Message.addToRepeatedField(this, 1, value, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods.prototype.clearMethodsList = function() { - return this.setMethodsList([]); -}; - - -/** - * optional google.protobuf.StringValue name = 1; - * @return {?proto.google.protobuf.StringValue} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.getName = function() { - return /** @type{?proto.google.protobuf.StringValue} */ ( - jspb.Message.getWrapperField(this, google_protobuf_wrappers_pb.StringValue, 1)); -}; - - -/** - * @param {?proto.google.protobuf.StringValue|undefined} value - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this -*/ -proto.yorkie.v1.UpdatableProjectFields.prototype.setName = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.clearName = function() { - return this.setName(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.hasName = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional google.protobuf.StringValue auth_webhook_url = 2; - * @return {?proto.google.protobuf.StringValue} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.getAuthWebhookUrl = function() { - return /** @type{?proto.google.protobuf.StringValue} */ ( - jspb.Message.getWrapperField(this, google_protobuf_wrappers_pb.StringValue, 2)); -}; - - -/** - * @param {?proto.google.protobuf.StringValue|undefined} value - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this -*/ -proto.yorkie.v1.UpdatableProjectFields.prototype.setAuthWebhookUrl = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.clearAuthWebhookUrl = function() { - return this.setAuthWebhookUrl(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.hasAuthWebhookUrl = function() { - return jspb.Message.getField(this, 2) != null; -}; - - -/** - * optional AuthWebhookMethods auth_webhook_methods = 3; - * @return {?proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.getAuthWebhookMethods = function() { - return /** @type{?proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.UpdatableProjectFields.AuthWebhookMethods|undefined} value - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this -*/ -proto.yorkie.v1.UpdatableProjectFields.prototype.setAuthWebhookMethods = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.clearAuthWebhookMethods = function() { - return this.setAuthWebhookMethods(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.hasAuthWebhookMethods = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional google.protobuf.StringValue client_deactivate_threshold = 4; - * @return {?proto.google.protobuf.StringValue} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.getClientDeactivateThreshold = function() { - return /** @type{?proto.google.protobuf.StringValue} */ ( - jspb.Message.getWrapperField(this, google_protobuf_wrappers_pb.StringValue, 4)); -}; - - -/** - * @param {?proto.google.protobuf.StringValue|undefined} value - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this -*/ -proto.yorkie.v1.UpdatableProjectFields.prototype.setClientDeactivateThreshold = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.UpdatableProjectFields} returns this - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.clearClientDeactivateThreshold = function() { - return this.setClientDeactivateThreshold(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.UpdatableProjectFields.prototype.hasClientDeactivateThreshold = function() { - return jspb.Message.getField(this, 4) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.DocumentSummary.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DocumentSummary.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DocumentSummary} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DocumentSummary.toObject = function(includeInstance, msg) { - var f, obj = { - id: jspb.Message.getFieldWithDefault(msg, 1, ""), - key: jspb.Message.getFieldWithDefault(msg, 2, ""), - snapshot: jspb.Message.getFieldWithDefault(msg, 3, ""), - createdAt: (f = msg.getCreatedAt()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f), - accessedAt: (f = msg.getAccessedAt()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f), - updatedAt: (f = msg.getUpdatedAt()) && google_protobuf_timestamp_pb.Timestamp.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DocumentSummary} - */ -proto.yorkie.v1.DocumentSummary.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DocumentSummary; - return proto.yorkie.v1.DocumentSummary.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DocumentSummary} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DocumentSummary} - */ -proto.yorkie.v1.DocumentSummary.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setKey(value); - break; - case 3: - var value = /** @type {string} */ (reader.readString()); - msg.setSnapshot(value); - break; - case 4: - var value = new google_protobuf_timestamp_pb.Timestamp; - reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 5: - var value = new google_protobuf_timestamp_pb.Timestamp; - reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader); - msg.setAccessedAt(value); - break; - case 6: - var value = new google_protobuf_timestamp_pb.Timestamp; - reader.readMessage(value,google_protobuf_timestamp_pb.Timestamp.deserializeBinaryFromReader); - msg.setUpdatedAt(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DocumentSummary.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DocumentSummary.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DocumentSummary} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DocumentSummary.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getKey(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getSnapshot(); - if (f.length > 0) { - writer.writeString( - 3, - f - ); - } - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 4, - f, - google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter - ); - } - f = message.getAccessedAt(); - if (f != null) { - writer.writeMessage( - 5, - f, - google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter - ); - } - f = message.getUpdatedAt(); - if (f != null) { - writer.writeMessage( - 6, - f, - google_protobuf_timestamp_pb.Timestamp.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string id = 1; - * @return {string} - */ -proto.yorkie.v1.DocumentSummary.prototype.getId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DocumentSummary} returns this - */ -proto.yorkie.v1.DocumentSummary.prototype.setId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string key = 2; - * @return {string} - */ -proto.yorkie.v1.DocumentSummary.prototype.getKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DocumentSummary} returns this - */ -proto.yorkie.v1.DocumentSummary.prototype.setKey = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional string snapshot = 3; - * @return {string} - */ -proto.yorkie.v1.DocumentSummary.prototype.getSnapshot = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DocumentSummary} returns this - */ -proto.yorkie.v1.DocumentSummary.prototype.setSnapshot = function(value) { - return jspb.Message.setProto3StringField(this, 3, value); -}; - - -/** - * optional google.protobuf.Timestamp created_at = 4; - * @return {?proto.google.protobuf.Timestamp} - */ -proto.yorkie.v1.DocumentSummary.prototype.getCreatedAt = function() { - return /** @type{?proto.google.protobuf.Timestamp} */ ( - jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 4)); -}; - - -/** - * @param {?proto.google.protobuf.Timestamp|undefined} value - * @return {!proto.yorkie.v1.DocumentSummary} returns this -*/ -proto.yorkie.v1.DocumentSummary.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.DocumentSummary} returns this - */ -proto.yorkie.v1.DocumentSummary.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.DocumentSummary.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 4) != null; -}; - - -/** - * optional google.protobuf.Timestamp accessed_at = 5; - * @return {?proto.google.protobuf.Timestamp} - */ -proto.yorkie.v1.DocumentSummary.prototype.getAccessedAt = function() { - return /** @type{?proto.google.protobuf.Timestamp} */ ( - jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 5)); -}; - - -/** - * @param {?proto.google.protobuf.Timestamp|undefined} value - * @return {!proto.yorkie.v1.DocumentSummary} returns this -*/ -proto.yorkie.v1.DocumentSummary.prototype.setAccessedAt = function(value) { - return jspb.Message.setWrapperField(this, 5, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.DocumentSummary} returns this - */ -proto.yorkie.v1.DocumentSummary.prototype.clearAccessedAt = function() { - return this.setAccessedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.DocumentSummary.prototype.hasAccessedAt = function() { - return jspb.Message.getField(this, 5) != null; -}; - - -/** - * optional google.protobuf.Timestamp updated_at = 6; - * @return {?proto.google.protobuf.Timestamp} - */ -proto.yorkie.v1.DocumentSummary.prototype.getUpdatedAt = function() { - return /** @type{?proto.google.protobuf.Timestamp} */ ( - jspb.Message.getWrapperField(this, google_protobuf_timestamp_pb.Timestamp, 6)); -}; - - -/** - * @param {?proto.google.protobuf.Timestamp|undefined} value - * @return {!proto.yorkie.v1.DocumentSummary} returns this -*/ -proto.yorkie.v1.DocumentSummary.prototype.setUpdatedAt = function(value) { - return jspb.Message.setWrapperField(this, 6, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.DocumentSummary} returns this - */ -proto.yorkie.v1.DocumentSummary.prototype.clearUpdatedAt = function() { - return this.setUpdatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.DocumentSummary.prototype.hasUpdatedAt = function() { - return jspb.Message.getField(this, 6) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.PresenceChange.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.PresenceChange.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.PresenceChange} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.PresenceChange.toObject = function(includeInstance, msg) { - var f, obj = { - type: jspb.Message.getFieldWithDefault(msg, 1, 0), - presence: (f = msg.getPresence()) && proto.yorkie.v1.Presence.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.PresenceChange} - */ -proto.yorkie.v1.PresenceChange.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.PresenceChange; - return proto.yorkie.v1.PresenceChange.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.PresenceChange} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.PresenceChange} - */ -proto.yorkie.v1.PresenceChange.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {!proto.yorkie.v1.PresenceChange.ChangeType} */ (reader.readEnum()); - msg.setType(value); - break; - case 2: - var value = new proto.yorkie.v1.Presence; - reader.readMessage(value,proto.yorkie.v1.Presence.deserializeBinaryFromReader); - msg.setPresence(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.PresenceChange.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.PresenceChange.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.PresenceChange} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.PresenceChange.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 1, - f - ); - } - f = message.getPresence(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.yorkie.v1.Presence.serializeBinaryToWriter - ); - } -}; - - -/** - * @enum {number} - */ -proto.yorkie.v1.PresenceChange.ChangeType = { - CHANGE_TYPE_UNSPECIFIED: 0, - CHANGE_TYPE_PUT: 1, - CHANGE_TYPE_DELETE: 2, - CHANGE_TYPE_CLEAR: 3 -}; - -/** - * optional ChangeType type = 1; - * @return {!proto.yorkie.v1.PresenceChange.ChangeType} - */ -proto.yorkie.v1.PresenceChange.prototype.getType = function() { - return /** @type {!proto.yorkie.v1.PresenceChange.ChangeType} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); -}; - - -/** - * @param {!proto.yorkie.v1.PresenceChange.ChangeType} value - * @return {!proto.yorkie.v1.PresenceChange} returns this - */ -proto.yorkie.v1.PresenceChange.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 1, value); -}; - - -/** - * optional Presence presence = 2; - * @return {?proto.yorkie.v1.Presence} - */ -proto.yorkie.v1.PresenceChange.prototype.getPresence = function() { - return /** @type{?proto.yorkie.v1.Presence} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.Presence, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.Presence|undefined} value - * @return {!proto.yorkie.v1.PresenceChange} returns this -*/ -proto.yorkie.v1.PresenceChange.prototype.setPresence = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.PresenceChange} returns this - */ -proto.yorkie.v1.PresenceChange.prototype.clearPresence = function() { - return this.setPresence(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.PresenceChange.prototype.hasPresence = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Presence.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Presence.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Presence} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Presence.toObject = function(includeInstance, msg) { - var f, obj = { - dataMap: (f = msg.getDataMap()) ? f.toObject(includeInstance, undefined) : [] - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Presence} - */ -proto.yorkie.v1.Presence.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Presence; - return proto.yorkie.v1.Presence.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Presence} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Presence} - */ -proto.yorkie.v1.Presence.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = msg.getDataMap(); - reader.readMessage(value, function(message, reader) { - jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); - }); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Presence.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Presence.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Presence} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Presence.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getDataMap(true); - if (f && f.getLength() > 0) { - f.serializeBinary(1, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); - } -}; - - -/** - * map data = 1; - * @param {boolean=} opt_noLazyCreate Do not create the map if - * empty, instead returning `undefined` - * @return {!jspb.Map} - */ -proto.yorkie.v1.Presence.prototype.getDataMap = function(opt_noLazyCreate) { - return /** @type {!jspb.Map} */ ( - jspb.Message.getMapField(this, 1, opt_noLazyCreate, - null)); -}; - - -/** - * Clears values from the map. The map will be non-null. - * @return {!proto.yorkie.v1.Presence} returns this - */ -proto.yorkie.v1.Presence.prototype.clearDataMap = function() { - this.getDataMap().clear(); - return this; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.Checkpoint.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.Checkpoint.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.Checkpoint} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Checkpoint.toObject = function(includeInstance, msg) { - var f, obj = { - serverSeq: jspb.Message.getFieldWithDefault(msg, 1, "0"), - clientSeq: jspb.Message.getFieldWithDefault(msg, 2, 0) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.Checkpoint} - */ -proto.yorkie.v1.Checkpoint.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.Checkpoint; - return proto.yorkie.v1.Checkpoint.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.Checkpoint} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.Checkpoint} - */ -proto.yorkie.v1.Checkpoint.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readInt64String()); - msg.setServerSeq(value); - break; - case 2: - var value = /** @type {number} */ (reader.readUint32()); - msg.setClientSeq(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.Checkpoint.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.Checkpoint.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.Checkpoint} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.Checkpoint.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getServerSeq(); - if (parseInt(f, 10) !== 0) { - writer.writeInt64String( - 1, - f - ); - } - f = message.getClientSeq(); - if (f !== 0) { - writer.writeUint32( - 2, - f - ); - } -}; - - -/** - * optional int64 server_seq = 1; - * @return {string} - */ -proto.yorkie.v1.Checkpoint.prototype.getServerSeq = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.Checkpoint} returns this - */ -proto.yorkie.v1.Checkpoint.prototype.setServerSeq = function(value) { - return jspb.Message.setProto3StringIntField(this, 1, value); -}; - - -/** - * optional uint32 client_seq = 2; - * @return {number} - */ -proto.yorkie.v1.Checkpoint.prototype.getClientSeq = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.Checkpoint} returns this - */ -proto.yorkie.v1.Checkpoint.prototype.setClientSeq = function(value) { - return jspb.Message.setProto3IntField(this, 2, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TextNodePos.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TextNodePos.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TextNodePos} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TextNodePos.toObject = function(includeInstance, msg) { - var f, obj = { - createdAt: (f = msg.getCreatedAt()) && proto.yorkie.v1.TimeTicket.toObject(includeInstance, f), - offset: jspb.Message.getFieldWithDefault(msg, 2, 0), - relativeOffset: jspb.Message.getFieldWithDefault(msg, 3, 0) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.TextNodePos.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TextNodePos; - return proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TextNodePos} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TextNodePos} - */ -proto.yorkie.v1.TextNodePos.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.TimeTicket; - reader.readMessage(value,proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt32()); - msg.setOffset(value); - break; - case 3: - var value = /** @type {number} */ (reader.readInt32()); - msg.setRelativeOffset(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TextNodePos.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TextNodePos.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TextNodePos} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TextNodePos.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getCreatedAt(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter - ); - } - f = message.getOffset(); - if (f !== 0) { - writer.writeInt32( - 2, - f - ); - } - f = message.getRelativeOffset(); - if (f !== 0) { - writer.writeInt32( - 3, - f - ); - } -}; - - -/** - * optional TimeTicket created_at = 1; - * @return {?proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TextNodePos.prototype.getCreatedAt = function() { - return /** @type{?proto.yorkie.v1.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.TimeTicket, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.TimeTicket|undefined} value - * @return {!proto.yorkie.v1.TextNodePos} returns this -*/ -proto.yorkie.v1.TextNodePos.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.TextNodePos} returns this - */ -proto.yorkie.v1.TextNodePos.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.TextNodePos.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional int32 offset = 2; - * @return {number} - */ -proto.yorkie.v1.TextNodePos.prototype.getOffset = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.TextNodePos} returns this - */ -proto.yorkie.v1.TextNodePos.prototype.setOffset = function(value) { - return jspb.Message.setProto3IntField(this, 2, value); -}; - - -/** - * optional int32 relative_offset = 3; - * @return {number} - */ -proto.yorkie.v1.TextNodePos.prototype.getRelativeOffset = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.TextNodePos} returns this - */ -proto.yorkie.v1.TextNodePos.prototype.setRelativeOffset = function(value) { - return jspb.Message.setProto3IntField(this, 3, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.TimeTicket.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.TimeTicket.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.TimeTicket} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TimeTicket.toObject = function(includeInstance, msg) { - var f, obj = { - lamport: jspb.Message.getFieldWithDefault(msg, 1, "0"), - delimiter: jspb.Message.getFieldWithDefault(msg, 2, 0), - actorId: msg.getActorId_asB64() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TimeTicket.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.TimeTicket; - return proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.TimeTicket} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.TimeTicket} - */ -proto.yorkie.v1.TimeTicket.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readInt64String()); - msg.setLamport(value); - break; - case 2: - var value = /** @type {number} */ (reader.readUint32()); - msg.setDelimiter(value); - break; - case 3: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setActorId(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.TimeTicket.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.TimeTicket.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.TimeTicket} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.TimeTicket.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getLamport(); - if (parseInt(f, 10) !== 0) { - writer.writeInt64String( - 1, - f - ); - } - f = message.getDelimiter(); - if (f !== 0) { - writer.writeUint32( - 2, - f - ); - } - f = message.getActorId_asU8(); - if (f.length > 0) { - writer.writeBytes( - 3, - f - ); - } -}; - - -/** - * optional int64 lamport = 1; - * @return {string} - */ -proto.yorkie.v1.TimeTicket.prototype.getLamport = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.TimeTicket} returns this - */ -proto.yorkie.v1.TimeTicket.prototype.setLamport = function(value) { - return jspb.Message.setProto3StringIntField(this, 1, value); -}; - - -/** - * optional uint32 delimiter = 2; - * @return {number} - */ -proto.yorkie.v1.TimeTicket.prototype.getDelimiter = function() { - return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); -}; - - -/** - * @param {number} value - * @return {!proto.yorkie.v1.TimeTicket} returns this - */ -proto.yorkie.v1.TimeTicket.prototype.setDelimiter = function(value) { - return jspb.Message.setProto3IntField(this, 2, value); -}; - - -/** - * optional bytes actor_id = 3; - * @return {string} - */ -proto.yorkie.v1.TimeTicket.prototype.getActorId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * optional bytes actor_id = 3; - * This is a type-conversion wrapper around `getActorId()` - * @return {string} - */ -proto.yorkie.v1.TimeTicket.prototype.getActorId_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getActorId())); -}; - - -/** - * optional bytes actor_id = 3; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getActorId()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.TimeTicket.prototype.getActorId_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getActorId())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.TimeTicket} returns this - */ -proto.yorkie.v1.TimeTicket.prototype.setActorId = function(value) { - return jspb.Message.setProto3BytesField(this, 3, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.DocEventBody.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DocEventBody.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DocEventBody} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DocEventBody.toObject = function(includeInstance, msg) { - var f, obj = { - topic: jspb.Message.getFieldWithDefault(msg, 1, ""), - payload: msg.getPayload_asB64() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DocEventBody} - */ -proto.yorkie.v1.DocEventBody.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DocEventBody; - return proto.yorkie.v1.DocEventBody.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DocEventBody} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DocEventBody} - */ -proto.yorkie.v1.DocEventBody.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setTopic(value); - break; - case 2: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setPayload(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DocEventBody.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DocEventBody.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DocEventBody} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DocEventBody.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getTopic(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getPayload_asU8(); - if (f.length > 0) { - writer.writeBytes( - 2, - f - ); - } -}; - - -/** - * optional string topic = 1; - * @return {string} - */ -proto.yorkie.v1.DocEventBody.prototype.getTopic = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DocEventBody} returns this - */ -proto.yorkie.v1.DocEventBody.prototype.setTopic = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional bytes payload = 2; - * @return {string} - */ -proto.yorkie.v1.DocEventBody.prototype.getPayload = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * optional bytes payload = 2; - * This is a type-conversion wrapper around `getPayload()` - * @return {string} - */ -proto.yorkie.v1.DocEventBody.prototype.getPayload_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getPayload())); -}; - - -/** - * optional bytes payload = 2; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getPayload()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.DocEventBody.prototype.getPayload_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getPayload())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.DocEventBody} returns this - */ -proto.yorkie.v1.DocEventBody.prototype.setPayload = function(value) { - return jspb.Message.setProto3BytesField(this, 2, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.DocEvent.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DocEvent.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DocEvent} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DocEvent.toObject = function(includeInstance, msg) { - var f, obj = { - type: jspb.Message.getFieldWithDefault(msg, 1, 0), - publisher: jspb.Message.getFieldWithDefault(msg, 2, ""), - body: (f = msg.getBody()) && proto.yorkie.v1.DocEventBody.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DocEvent} - */ -proto.yorkie.v1.DocEvent.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DocEvent; - return proto.yorkie.v1.DocEvent.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DocEvent} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DocEvent} - */ -proto.yorkie.v1.DocEvent.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {!proto.yorkie.v1.DocEventType} */ (reader.readEnum()); - msg.setType(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setPublisher(value); - break; - case 3: - var value = new proto.yorkie.v1.DocEventBody; - reader.readMessage(value,proto.yorkie.v1.DocEventBody.deserializeBinaryFromReader); - msg.setBody(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DocEvent.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DocEvent.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DocEvent} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DocEvent.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 1, - f - ); - } - f = message.getPublisher(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getBody(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.yorkie.v1.DocEventBody.serializeBinaryToWriter - ); - } -}; - - -/** - * optional DocEventType type = 1; - * @return {!proto.yorkie.v1.DocEventType} - */ -proto.yorkie.v1.DocEvent.prototype.getType = function() { - return /** @type {!proto.yorkie.v1.DocEventType} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); -}; - - -/** - * @param {!proto.yorkie.v1.DocEventType} value - * @return {!proto.yorkie.v1.DocEvent} returns this - */ -proto.yorkie.v1.DocEvent.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 1, value); -}; - - -/** - * optional string publisher = 2; - * @return {string} - */ -proto.yorkie.v1.DocEvent.prototype.getPublisher = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DocEvent} returns this - */ -proto.yorkie.v1.DocEvent.prototype.setPublisher = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional DocEventBody body = 3; - * @return {?proto.yorkie.v1.DocEventBody} - */ -proto.yorkie.v1.DocEvent.prototype.getBody = function() { - return /** @type{?proto.yorkie.v1.DocEventBody} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.DocEventBody, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.DocEventBody|undefined} value - * @return {!proto.yorkie.v1.DocEvent} returns this -*/ -proto.yorkie.v1.DocEvent.prototype.setBody = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.DocEvent} returns this - */ -proto.yorkie.v1.DocEvent.prototype.clearBody = function() { - return this.setBody(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.DocEvent.prototype.hasBody = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * @enum {number} - */ -proto.yorkie.v1.ValueType = { - VALUE_TYPE_NULL: 0, - VALUE_TYPE_BOOLEAN: 1, - VALUE_TYPE_INTEGER: 2, - VALUE_TYPE_LONG: 3, - VALUE_TYPE_DOUBLE: 4, - VALUE_TYPE_STRING: 5, - VALUE_TYPE_BYTES: 6, - VALUE_TYPE_DATE: 7, - VALUE_TYPE_JSON_OBJECT: 8, - VALUE_TYPE_JSON_ARRAY: 9, - VALUE_TYPE_TEXT: 10, - VALUE_TYPE_INTEGER_CNT: 11, - VALUE_TYPE_LONG_CNT: 12, - VALUE_TYPE_TREE: 13 -}; - -/** - * @enum {number} - */ -proto.yorkie.v1.DocEventType = { - DOC_EVENT_TYPE_DOCUMENT_CHANGED: 0, - DOC_EVENT_TYPE_DOCUMENT_WATCHED: 1, - DOC_EVENT_TYPE_DOCUMENT_UNWATCHED: 2, - DOC_EVENT_TYPE_DOCUMENT_BROADCAST: 3 -}; - -goog.object.extend(exports, proto.yorkie.v1); +const Project = proto3.makeMessageType( + "yorkie.v1.Project", + () => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "public_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "secret_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 5, name: "auth_webhook_url", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 6, name: "auth_webhook_methods", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + { no: 7, name: "client_deactivate_threshold", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 8, name: "created_at", kind: "message", T: Timestamp }, + { no: 9, name: "updated_at", kind: "message", T: Timestamp }, + ], +); + +/** + * @generated from message yorkie.v1.UpdatableProjectFields + */ +const UpdatableProjectFields = proto3.makeMessageType( + "yorkie.v1.UpdatableProjectFields", + () => [ + { no: 1, name: "name", kind: "message", T: StringValue }, + { no: 2, name: "auth_webhook_url", kind: "message", T: StringValue }, + { no: 3, name: "auth_webhook_methods", kind: "message", T: UpdatableProjectFields_AuthWebhookMethods }, + { no: 4, name: "client_deactivate_threshold", kind: "message", T: StringValue }, + ], +); + +/** + * @generated from message yorkie.v1.UpdatableProjectFields.AuthWebhookMethods + */ +const UpdatableProjectFields_AuthWebhookMethods = proto3.makeMessageType( + "yorkie.v1.UpdatableProjectFields.AuthWebhookMethods", + () => [ + { no: 1, name: "methods", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ], + {localName: "UpdatableProjectFields_AuthWebhookMethods"}, +); + +/** + * @generated from message yorkie.v1.DocumentSummary + */ +const DocumentSummary = proto3.makeMessageType( + "yorkie.v1.DocumentSummary", + () => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "snapshot", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "created_at", kind: "message", T: Timestamp }, + { no: 5, name: "accessed_at", kind: "message", T: Timestamp }, + { no: 6, name: "updated_at", kind: "message", T: Timestamp }, + ], +); + +/** + * @generated from message yorkie.v1.PresenceChange + */ +const PresenceChange = proto3.makeMessageType( + "yorkie.v1.PresenceChange", + () => [ + { no: 1, name: "type", kind: "enum", T: proto3.getEnumType(PresenceChange_ChangeType) }, + { no: 2, name: "presence", kind: "message", T: Presence }, + ], +); + +/** + * @generated from enum yorkie.v1.PresenceChange.ChangeType + */ +const PresenceChange_ChangeType = proto3.makeEnum( + "yorkie.v1.PresenceChange.ChangeType", + [ + {no: 0, name: "CHANGE_TYPE_UNSPECIFIED", localName: "UNSPECIFIED"}, + {no: 1, name: "CHANGE_TYPE_PUT", localName: "PUT"}, + {no: 2, name: "CHANGE_TYPE_DELETE", localName: "DELETE"}, + {no: 3, name: "CHANGE_TYPE_CLEAR", localName: "CLEAR"}, + ], +); + +/** + * @generated from message yorkie.v1.Presence + */ +const Presence = proto3.makeMessageType( + "yorkie.v1.Presence", + () => [ + { no: 1, name: "data", kind: "map", K: 9 /* ScalarType.STRING */, V: {kind: "scalar", T: 9 /* ScalarType.STRING */} }, + ], +); + +/** + * @generated from message yorkie.v1.Checkpoint + */ +const Checkpoint = proto3.makeMessageType( + "yorkie.v1.Checkpoint", + () => [ + { no: 1, name: "server_seq", kind: "scalar", T: 3 /* ScalarType.INT64 */, L: 1 /* LongType.STRING */ }, + { no: 2, name: "client_seq", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + ], +); + +/** + * @generated from message yorkie.v1.TextNodePos + */ +const TextNodePos = proto3.makeMessageType( + "yorkie.v1.TextNodePos", + () => [ + { no: 1, name: "created_at", kind: "message", T: TimeTicket }, + { no: 2, name: "offset", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 3, name: "relative_offset", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + ], +); + +/** + * @generated from message yorkie.v1.TimeTicket + */ +const TimeTicket = proto3.makeMessageType( + "yorkie.v1.TimeTicket", + () => [ + { no: 1, name: "lamport", kind: "scalar", T: 3 /* ScalarType.INT64 */, L: 1 /* LongType.STRING */ }, + { no: 2, name: "delimiter", kind: "scalar", T: 13 /* ScalarType.UINT32 */ }, + { no: 3, name: "actor_id", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + ], +); + +/** + * @generated from message yorkie.v1.DocEventBody + */ +const DocEventBody = proto3.makeMessageType( + "yorkie.v1.DocEventBody", + () => [ + { no: 1, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "payload", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + ], +); + +/** + * @generated from message yorkie.v1.DocEvent + */ +const DocEvent = proto3.makeMessageType( + "yorkie.v1.DocEvent", + () => [ + { no: 1, name: "type", kind: "enum", T: proto3.getEnumType(DocEventType) }, + { no: 2, name: "publisher", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "body", kind: "message", T: DocEventBody }, + ], +); + + +exports.ValueType = ValueType; +exports.DocEventType = DocEventType; +exports.Snapshot = Snapshot; +exports.ChangePack = ChangePack; +exports.Change = Change; +exports.ChangeID = ChangeID; +exports.Operation = Operation; +exports.Operation_Set = Operation_Set; +exports.Operation_Add = Operation_Add; +exports.Operation_Move = Operation_Move; +exports.Operation_Remove = Operation_Remove; +exports.Operation_Edit = Operation_Edit; +exports.Operation_Select = Operation_Select; +exports.Operation_Style = Operation_Style; +exports.Operation_Increase = Operation_Increase; +exports.Operation_TreeEdit = Operation_TreeEdit; +exports.Operation_TreeStyle = Operation_TreeStyle; +exports.JSONElementSimple = JSONElementSimple; +exports.JSONElement = JSONElement; +exports.JSONElement_JSONObject = JSONElement_JSONObject; +exports.JSONElement_JSONArray = JSONElement_JSONArray; +exports.JSONElement_Primitive = JSONElement_Primitive; +exports.JSONElement_Text = JSONElement_Text; +exports.JSONElement_Counter = JSONElement_Counter; +exports.JSONElement_Tree = JSONElement_Tree; +exports.RHTNode = RHTNode; +exports.RGANode = RGANode; +exports.NodeAttr = NodeAttr; +exports.TextNode = TextNode; +exports.TextNodeID = TextNodeID; +exports.TreeNode = TreeNode; +exports.TreeNodes = TreeNodes; +exports.TreeNodeID = TreeNodeID; +exports.TreePos = TreePos; +exports.User = User; +exports.Project = Project; +exports.UpdatableProjectFields = UpdatableProjectFields; +exports.UpdatableProjectFields_AuthWebhookMethods = UpdatableProjectFields_AuthWebhookMethods; +exports.DocumentSummary = DocumentSummary; +exports.PresenceChange = PresenceChange; +exports.PresenceChange_ChangeType = PresenceChange_ChangeType; +exports.Presence = Presence; +exports.Checkpoint = Checkpoint; +exports.TextNodePos = TextNodePos; +exports.TimeTicket = TimeTicket; +exports.DocEventBody = DocEventBody; +exports.DocEvent = DocEvent; diff --git a/src/api/yorkie/v1/yorkie.proto b/src/api/yorkie/v1/yorkie.proto index da71d6a11..279f96f98 100644 --- a/src/api/yorkie/v1/yorkie.proto +++ b/src/api/yorkie/v1/yorkie.proto @@ -17,9 +17,9 @@ syntax = "proto3"; package yorkie.v1; -import "yorkie/v1/resources.proto"; +import "src/api/yorkie/v1/resources.proto"; -option go_package = ".;v1"; +option go_package = "github.com/yorkie-team/yorkie/api/yorkie/v1;v1"; option java_multiple_files = true; option java_package = "dev.yorkie.api.v1"; diff --git a/src/api/yorkie/v1/yorkie_connect.d.ts b/src/api/yorkie/v1/yorkie_connect.d.ts new file mode 100644 index 000000000..89315b90a --- /dev/null +++ b/src/api/yorkie/v1/yorkie_connect.d.ts @@ -0,0 +1,106 @@ +// +// Copyright 2020 The Yorkie Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-connect-es v1.2.0 with parameter "target=js+dts,js_import_style=legacy_commonjs" +// @generated from file src/api/yorkie/v1/yorkie.proto (package yorkie.v1, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import { ActivateClientRequest, ActivateClientResponse, AttachDocumentRequest, AttachDocumentResponse, BroadcastRequest, BroadcastResponse, DeactivateClientRequest, DeactivateClientResponse, DetachDocumentRequest, DetachDocumentResponse, PushPullChangesRequest, PushPullChangesResponse, RemoveDocumentRequest, RemoveDocumentResponse, WatchDocumentRequest, WatchDocumentResponse } from "./yorkie_pb.js"; +import { MethodKind } from "@bufbuild/protobuf"; + +/** + * Yorkie is a service that provides a API for SDKs. + * + * @generated from service yorkie.v1.YorkieService + */ +export declare const YorkieService: { + readonly typeName: "yorkie.v1.YorkieService", + readonly methods: { + /** + * @generated from rpc yorkie.v1.YorkieService.ActivateClient + */ + readonly activateClient: { + readonly name: "ActivateClient", + readonly I: typeof ActivateClientRequest, + readonly O: typeof ActivateClientResponse, + readonly kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.DeactivateClient + */ + readonly deactivateClient: { + readonly name: "DeactivateClient", + readonly I: typeof DeactivateClientRequest, + readonly O: typeof DeactivateClientResponse, + readonly kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.AttachDocument + */ + readonly attachDocument: { + readonly name: "AttachDocument", + readonly I: typeof AttachDocumentRequest, + readonly O: typeof AttachDocumentResponse, + readonly kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.DetachDocument + */ + readonly detachDocument: { + readonly name: "DetachDocument", + readonly I: typeof DetachDocumentRequest, + readonly O: typeof DetachDocumentResponse, + readonly kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.RemoveDocument + */ + readonly removeDocument: { + readonly name: "RemoveDocument", + readonly I: typeof RemoveDocumentRequest, + readonly O: typeof RemoveDocumentResponse, + readonly kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.PushPullChanges + */ + readonly pushPullChanges: { + readonly name: "PushPullChanges", + readonly I: typeof PushPullChangesRequest, + readonly O: typeof PushPullChangesResponse, + readonly kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.WatchDocument + */ + readonly watchDocument: { + readonly name: "WatchDocument", + readonly I: typeof WatchDocumentRequest, + readonly O: typeof WatchDocumentResponse, + readonly kind: MethodKind.ServerStreaming, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.Broadcast + */ + readonly broadcast: { + readonly name: "Broadcast", + readonly I: typeof BroadcastRequest, + readonly O: typeof BroadcastResponse, + readonly kind: MethodKind.Unary, + }, + } +}; + diff --git a/src/api/yorkie/v1/yorkie_connect.js b/src/api/yorkie/v1/yorkie_connect.js new file mode 100644 index 000000000..2e1be4fdb --- /dev/null +++ b/src/api/yorkie/v1/yorkie_connect.js @@ -0,0 +1,111 @@ +// +// Copyright 2020 The Yorkie Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-connect-es v1.2.0 with parameter "target=js+dts,js_import_style=legacy_commonjs" +// @generated from file src/api/yorkie/v1/yorkie.proto (package yorkie.v1, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); + +const { ActivateClientRequest, ActivateClientResponse, AttachDocumentRequest, AttachDocumentResponse, BroadcastRequest, BroadcastResponse, DeactivateClientRequest, DeactivateClientResponse, DetachDocumentRequest, DetachDocumentResponse, PushPullChangesRequest, PushPullChangesResponse, RemoveDocumentRequest, RemoveDocumentResponse, WatchDocumentRequest, WatchDocumentResponse } = require("./yorkie_pb.js"); +const { MethodKind } = require("@bufbuild/protobuf"); + +/** + * Yorkie is a service that provides a API for SDKs. + * + * @generated from service yorkie.v1.YorkieService + */ +const YorkieService = { + typeName: "yorkie.v1.YorkieService", + methods: { + /** + * @generated from rpc yorkie.v1.YorkieService.ActivateClient + */ + activateClient: { + name: "ActivateClient", + I: ActivateClientRequest, + O: ActivateClientResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.DeactivateClient + */ + deactivateClient: { + name: "DeactivateClient", + I: DeactivateClientRequest, + O: DeactivateClientResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.AttachDocument + */ + attachDocument: { + name: "AttachDocument", + I: AttachDocumentRequest, + O: AttachDocumentResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.DetachDocument + */ + detachDocument: { + name: "DetachDocument", + I: DetachDocumentRequest, + O: DetachDocumentResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.RemoveDocument + */ + removeDocument: { + name: "RemoveDocument", + I: RemoveDocumentRequest, + O: RemoveDocumentResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.PushPullChanges + */ + pushPullChanges: { + name: "PushPullChanges", + I: PushPullChangesRequest, + O: PushPullChangesResponse, + kind: MethodKind.Unary, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.WatchDocument + */ + watchDocument: { + name: "WatchDocument", + I: WatchDocumentRequest, + O: WatchDocumentResponse, + kind: MethodKind.ServerStreaming, + }, + /** + * @generated from rpc yorkie.v1.YorkieService.Broadcast + */ + broadcast: { + name: "Broadcast", + I: BroadcastRequest, + O: BroadcastResponse, + kind: MethodKind.Unary, + }, + } +}; + + +exports.YorkieService = YorkieService; diff --git a/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts b/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts deleted file mode 100644 index 11089c8da..000000000 --- a/src/api/yorkie/v1/yorkie_grpc_web_pb.d.ts +++ /dev/null @@ -1,113 +0,0 @@ -import * as grpcWeb from 'grpc-web'; - -import * as yorkie_v1_yorkie_pb from '../../yorkie/v1/yorkie_pb'; - - -export class YorkieServiceClient { - constructor (hostname: string, - credentials?: null | { [index: string]: string; }, - options?: null | { [index: string]: any; }); - - activateClient( - request: yorkie_v1_yorkie_pb.ActivateClientRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.ActivateClientResponse) => void - ): grpcWeb.ClientReadableStream; - - deactivateClient( - request: yorkie_v1_yorkie_pb.DeactivateClientRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.DeactivateClientResponse) => void - ): grpcWeb.ClientReadableStream; - - attachDocument( - request: yorkie_v1_yorkie_pb.AttachDocumentRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.AttachDocumentResponse) => void - ): grpcWeb.ClientReadableStream; - - detachDocument( - request: yorkie_v1_yorkie_pb.DetachDocumentRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.DetachDocumentResponse) => void - ): grpcWeb.ClientReadableStream; - - removeDocument( - request: yorkie_v1_yorkie_pb.RemoveDocumentRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.RemoveDocumentResponse) => void - ): grpcWeb.ClientReadableStream; - - pushPullChanges( - request: yorkie_v1_yorkie_pb.PushPullChangesRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.PushPullChangesResponse) => void - ): grpcWeb.ClientReadableStream; - - watchDocument( - request: yorkie_v1_yorkie_pb.WatchDocumentRequest, - metadata?: grpcWeb.Metadata - ): grpcWeb.ClientReadableStream; - - broadcast( - request: yorkie_v1_yorkie_pb.BroadcastRequest, - metadata: grpcWeb.Metadata | undefined, - callback: (err: grpcWeb.RpcError, - response: yorkie_v1_yorkie_pb.BroadcastResponse) => void - ): grpcWeb.ClientReadableStream; - -} - -export class YorkieServicePromiseClient { - constructor (hostname: string, - credentials?: null | { [index: string]: string; }, - options?: null | { [index: string]: any; }); - - activateClient( - request: yorkie_v1_yorkie_pb.ActivateClientRequest, - metadata?: grpcWeb.Metadata - ): Promise; - - deactivateClient( - request: yorkie_v1_yorkie_pb.DeactivateClientRequest, - metadata?: grpcWeb.Metadata - ): Promise; - - attachDocument( - request: yorkie_v1_yorkie_pb.AttachDocumentRequest, - metadata?: grpcWeb.Metadata - ): Promise; - - detachDocument( - request: yorkie_v1_yorkie_pb.DetachDocumentRequest, - metadata?: grpcWeb.Metadata - ): Promise; - - removeDocument( - request: yorkie_v1_yorkie_pb.RemoveDocumentRequest, - metadata?: grpcWeb.Metadata - ): Promise; - - pushPullChanges( - request: yorkie_v1_yorkie_pb.PushPullChangesRequest, - metadata?: grpcWeb.Metadata - ): Promise; - - watchDocument( - request: yorkie_v1_yorkie_pb.WatchDocumentRequest, - metadata?: grpcWeb.Metadata - ): grpcWeb.ClientReadableStream; - - broadcast( - request: yorkie_v1_yorkie_pb.BroadcastRequest, - metadata?: grpcWeb.Metadata - ): Promise; - -} - diff --git a/src/api/yorkie/v1/yorkie_grpc_web_pb.js b/src/api/yorkie/v1/yorkie_grpc_web_pb.js deleted file mode 100644 index 89725d283..000000000 --- a/src/api/yorkie/v1/yorkie_grpc_web_pb.js +++ /dev/null @@ -1,564 +0,0 @@ -/** - * @fileoverview gRPC-Web generated client stub for yorkie.v1 - * @enhanceable - * @public - */ - -// Code generated by protoc-gen-grpc-web. DO NOT EDIT. -// versions: -// protoc-gen-grpc-web v1.4.2 -// protoc v4.24.4 -// source: yorkie/v1/yorkie.proto - - -/* eslint-disable */ -// @ts-nocheck - - - -const grpc = {}; -grpc.web = require('grpc-web'); - - -var yorkie_v1_resources_pb = require('../../yorkie/v1/resources_pb.js') -const proto = {}; -proto.yorkie = {}; -proto.yorkie.v1 = require('./yorkie_pb.js'); - -/** - * @param {string} hostname - * @param {?Object} credentials - * @param {?grpc.web.ClientOptions} options - * @constructor - * @struct - * @final - */ -proto.yorkie.v1.YorkieServiceClient = - function(hostname, credentials, options) { - if (!options) options = {}; - options.format = 'text'; - - /** - * @private @const {!grpc.web.GrpcWebClientBase} The client - */ - this.client_ = new grpc.web.GrpcWebClientBase(options); - - /** - * @private @const {string} The hostname - */ - this.hostname_ = hostname.replace(/\/+$/, ''); - -}; - - -/** - * @param {string} hostname - * @param {?Object} credentials - * @param {?grpc.web.ClientOptions} options - * @constructor - * @struct - * @final - */ -proto.yorkie.v1.YorkieServicePromiseClient = - function(hostname, credentials, options) { - if (!options) options = {}; - options.format = 'text'; - - /** - * @private @const {!grpc.web.GrpcWebClientBase} The client - */ - this.client_ = new grpc.web.GrpcWebClientBase(options); - - /** - * @private @const {string} The hostname - */ - this.hostname_ = hostname.replace(/\/+$/, ''); - -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.ActivateClientRequest, - * !proto.yorkie.v1.ActivateClientResponse>} - */ -const methodDescriptor_YorkieService_ActivateClient = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/ActivateClient', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.ActivateClientRequest, - proto.yorkie.v1.ActivateClientResponse, - /** - * @param {!proto.yorkie.v1.ActivateClientRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.ActivateClientResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.ActivateClientRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.ActivateClientResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.activateClient = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/ActivateClient', - request, - metadata || {}, - methodDescriptor_YorkieService_ActivateClient, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.ActivateClientRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.activateClient = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/ActivateClient', - request, - metadata || {}, - methodDescriptor_YorkieService_ActivateClient); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.DeactivateClientRequest, - * !proto.yorkie.v1.DeactivateClientResponse>} - */ -const methodDescriptor_YorkieService_DeactivateClient = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/DeactivateClient', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.DeactivateClientRequest, - proto.yorkie.v1.DeactivateClientResponse, - /** - * @param {!proto.yorkie.v1.DeactivateClientRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.DeactivateClientResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.DeactivateClientRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.DeactivateClientResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.deactivateClient = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/DeactivateClient', - request, - metadata || {}, - methodDescriptor_YorkieService_DeactivateClient, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.DeactivateClientRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.deactivateClient = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/DeactivateClient', - request, - metadata || {}, - methodDescriptor_YorkieService_DeactivateClient); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.AttachDocumentRequest, - * !proto.yorkie.v1.AttachDocumentResponse>} - */ -const methodDescriptor_YorkieService_AttachDocument = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/AttachDocument', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.AttachDocumentRequest, - proto.yorkie.v1.AttachDocumentResponse, - /** - * @param {!proto.yorkie.v1.AttachDocumentRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.AttachDocumentResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.AttachDocumentRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.AttachDocumentResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.attachDocument = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/AttachDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_AttachDocument, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.AttachDocumentRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.attachDocument = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/AttachDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_AttachDocument); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.DetachDocumentRequest, - * !proto.yorkie.v1.DetachDocumentResponse>} - */ -const methodDescriptor_YorkieService_DetachDocument = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/DetachDocument', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.DetachDocumentRequest, - proto.yorkie.v1.DetachDocumentResponse, - /** - * @param {!proto.yorkie.v1.DetachDocumentRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.DetachDocumentResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.DetachDocumentRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.DetachDocumentResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.detachDocument = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/DetachDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_DetachDocument, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.DetachDocumentRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.detachDocument = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/DetachDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_DetachDocument); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.RemoveDocumentRequest, - * !proto.yorkie.v1.RemoveDocumentResponse>} - */ -const methodDescriptor_YorkieService_RemoveDocument = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/RemoveDocument', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.RemoveDocumentRequest, - proto.yorkie.v1.RemoveDocumentResponse, - /** - * @param {!proto.yorkie.v1.RemoveDocumentRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.RemoveDocumentResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.RemoveDocumentRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.RemoveDocumentResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.removeDocument = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/RemoveDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_RemoveDocument, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.RemoveDocumentRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.removeDocument = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/RemoveDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_RemoveDocument); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.PushPullChangesRequest, - * !proto.yorkie.v1.PushPullChangesResponse>} - */ -const methodDescriptor_YorkieService_PushPullChanges = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/PushPullChanges', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.PushPullChangesRequest, - proto.yorkie.v1.PushPullChangesResponse, - /** - * @param {!proto.yorkie.v1.PushPullChangesRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.PushPullChangesResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.PushPullChangesRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.PushPullChangesResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.pushPullChanges = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/PushPullChanges', - request, - metadata || {}, - methodDescriptor_YorkieService_PushPullChanges, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.PushPullChangesRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.pushPullChanges = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/PushPullChanges', - request, - metadata || {}, - methodDescriptor_YorkieService_PushPullChanges); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.WatchDocumentRequest, - * !proto.yorkie.v1.WatchDocumentResponse>} - */ -const methodDescriptor_YorkieService_WatchDocument = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/WatchDocument', - grpc.web.MethodType.SERVER_STREAMING, - proto.yorkie.v1.WatchDocumentRequest, - proto.yorkie.v1.WatchDocumentResponse, - /** - * @param {!proto.yorkie.v1.WatchDocumentRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.WatchDocumentResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.WatchDocumentRequest} request The request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!grpc.web.ClientReadableStream} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.watchDocument = - function(request, metadata) { - return this.client_.serverStreaming(this.hostname_ + - '/yorkie.v1.YorkieService/WatchDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_WatchDocument); -}; - - -/** - * @param {!proto.yorkie.v1.WatchDocumentRequest} request The request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!grpc.web.ClientReadableStream} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.watchDocument = - function(request, metadata) { - return this.client_.serverStreaming(this.hostname_ + - '/yorkie.v1.YorkieService/WatchDocument', - request, - metadata || {}, - methodDescriptor_YorkieService_WatchDocument); -}; - - -/** - * @const - * @type {!grpc.web.MethodDescriptor< - * !proto.yorkie.v1.BroadcastRequest, - * !proto.yorkie.v1.BroadcastResponse>} - */ -const methodDescriptor_YorkieService_Broadcast = new grpc.web.MethodDescriptor( - '/yorkie.v1.YorkieService/Broadcast', - grpc.web.MethodType.UNARY, - proto.yorkie.v1.BroadcastRequest, - proto.yorkie.v1.BroadcastResponse, - /** - * @param {!proto.yorkie.v1.BroadcastRequest} request - * @return {!Uint8Array} - */ - function(request) { - return request.serializeBinary(); - }, - proto.yorkie.v1.BroadcastResponse.deserializeBinary -); - - -/** - * @param {!proto.yorkie.v1.BroadcastRequest} request The - * request proto - * @param {?Object} metadata User defined - * call metadata - * @param {function(?grpc.web.RpcError, ?proto.yorkie.v1.BroadcastResponse)} - * callback The callback function(error, response) - * @return {!grpc.web.ClientReadableStream|undefined} - * The XHR Node Readable Stream - */ -proto.yorkie.v1.YorkieServiceClient.prototype.broadcast = - function(request, metadata, callback) { - return this.client_.rpcCall(this.hostname_ + - '/yorkie.v1.YorkieService/Broadcast', - request, - metadata || {}, - methodDescriptor_YorkieService_Broadcast, - callback); -}; - - -/** - * @param {!proto.yorkie.v1.BroadcastRequest} request The - * request proto - * @param {?Object=} metadata User defined - * call metadata - * @return {!Promise} - * Promise that resolves to the response - */ -proto.yorkie.v1.YorkieServicePromiseClient.prototype.broadcast = - function(request, metadata) { - return this.client_.unaryCall(this.hostname_ + - '/yorkie.v1.YorkieService/Broadcast', - request, - metadata || {}, - methodDescriptor_YorkieService_Broadcast); -}; - - -module.exports = proto.yorkie.v1; - diff --git a/src/api/yorkie/v1/yorkie_pb.d.ts b/src/api/yorkie/v1/yorkie_pb.d.ts index 0a3992403..0c685f6ad 100644 --- a/src/api/yorkie/v1/yorkie_pb.d.ts +++ b/src/api/yorkie/v1/yorkie_pb.d.ts @@ -1,396 +1,504 @@ -import * as jspb from 'google-protobuf' +// +// Copyright 2020 The Yorkie Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -import * as yorkie_v1_resources_pb from '../../yorkie/v1/resources_pb'; +// @generated by protoc-gen-es v1.6.0 with parameter "target=js+dts,js_import_style=legacy_commonjs" +// @generated from file src/api/yorkie/v1/yorkie.proto (package yorkie.v1, syntax proto3) +/* eslint-disable */ +// @ts-nocheck +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; +import { Message, proto3 } from "@bufbuild/protobuf"; +import type { ChangePack, DocEvent } from "./resources_pb.js"; -export class ActivateClientRequest extends jspb.Message { - getClientKey(): string; - setClientKey(value: string): ActivateClientRequest; +/** + * @generated from message yorkie.v1.ActivateClientRequest + */ +export declare class ActivateClientRequest extends Message { + /** + * @generated from field: string client_key = 1; + */ + clientKey: string; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): ActivateClientRequest.AsObject; - static toObject(includeInstance: boolean, msg: ActivateClientRequest): ActivateClientRequest.AsObject; - static serializeBinaryToWriter(message: ActivateClientRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): ActivateClientRequest; - static deserializeBinaryFromReader(message: ActivateClientRequest, reader: jspb.BinaryReader): ActivateClientRequest; -} + constructor(data?: PartialMessage); -export namespace ActivateClientRequest { - export type AsObject = { - clientKey: string, - } -} + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.ActivateClientRequest"; + static readonly fields: FieldList; -export class ActivateClientResponse extends jspb.Message { - getClientId(): string; - setClientId(value: string): ActivateClientResponse; + static fromBinary(bytes: Uint8Array, options?: Partial): ActivateClientRequest; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): ActivateClientResponse.AsObject; - static toObject(includeInstance: boolean, msg: ActivateClientResponse): ActivateClientResponse.AsObject; - static serializeBinaryToWriter(message: ActivateClientResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): ActivateClientResponse; - static deserializeBinaryFromReader(message: ActivateClientResponse, reader: jspb.BinaryReader): ActivateClientResponse; -} + static fromJson(jsonValue: JsonValue, options?: Partial): ActivateClientRequest; -export namespace ActivateClientResponse { - export type AsObject = { - clientId: string, - } + static fromJsonString(jsonString: string, options?: Partial): ActivateClientRequest; + + static equals(a: ActivateClientRequest | PlainMessage | undefined, b: ActivateClientRequest | PlainMessage | undefined): boolean; } -export class DeactivateClientRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): DeactivateClientRequest; +/** + * @generated from message yorkie.v1.ActivateClientResponse + */ +export declare class ActivateClientResponse extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DeactivateClientRequest.AsObject; - static toObject(includeInstance: boolean, msg: DeactivateClientRequest): DeactivateClientRequest.AsObject; - static serializeBinaryToWriter(message: DeactivateClientRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DeactivateClientRequest; - static deserializeBinaryFromReader(message: DeactivateClientRequest, reader: jspb.BinaryReader): DeactivateClientRequest; -} + constructor(data?: PartialMessage); -export namespace DeactivateClientRequest { - export type AsObject = { - clientId: string, - } -} + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.ActivateClientResponse"; + static readonly fields: FieldList; -export class DeactivateClientResponse extends jspb.Message { - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DeactivateClientResponse.AsObject; - static toObject(includeInstance: boolean, msg: DeactivateClientResponse): DeactivateClientResponse.AsObject; - static serializeBinaryToWriter(message: DeactivateClientResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DeactivateClientResponse; - static deserializeBinaryFromReader(message: DeactivateClientResponse, reader: jspb.BinaryReader): DeactivateClientResponse; -} + static fromBinary(bytes: Uint8Array, options?: Partial): ActivateClientResponse; -export namespace DeactivateClientResponse { - export type AsObject = { - } -} + static fromJson(jsonValue: JsonValue, options?: Partial): ActivateClientResponse; -export class AttachDocumentRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): AttachDocumentRequest; - - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): AttachDocumentRequest; - hasChangePack(): boolean; - clearChangePack(): AttachDocumentRequest; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): AttachDocumentRequest.AsObject; - static toObject(includeInstance: boolean, msg: AttachDocumentRequest): AttachDocumentRequest.AsObject; - static serializeBinaryToWriter(message: AttachDocumentRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): AttachDocumentRequest; - static deserializeBinaryFromReader(message: AttachDocumentRequest, reader: jspb.BinaryReader): AttachDocumentRequest; -} + static fromJsonString(jsonString: string, options?: Partial): ActivateClientResponse; -export namespace AttachDocumentRequest { - export type AsObject = { - clientId: string, - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - } + static equals(a: ActivateClientResponse | PlainMessage | undefined, b: ActivateClientResponse | PlainMessage | undefined): boolean; } -export class AttachDocumentResponse extends jspb.Message { - getDocumentId(): string; - setDocumentId(value: string): AttachDocumentResponse; - - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): AttachDocumentResponse; - hasChangePack(): boolean; - clearChangePack(): AttachDocumentResponse; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): AttachDocumentResponse.AsObject; - static toObject(includeInstance: boolean, msg: AttachDocumentResponse): AttachDocumentResponse.AsObject; - static serializeBinaryToWriter(message: AttachDocumentResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): AttachDocumentResponse; - static deserializeBinaryFromReader(message: AttachDocumentResponse, reader: jspb.BinaryReader): AttachDocumentResponse; -} +/** + * @generated from message yorkie.v1.DeactivateClientRequest + */ +export declare class DeactivateClientRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; -export namespace AttachDocumentResponse { - export type AsObject = { - documentId: string, - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - } -} + constructor(data?: PartialMessage); -export class DetachDocumentRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): DetachDocumentRequest; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DeactivateClientRequest"; + static readonly fields: FieldList; - getDocumentId(): string; - setDocumentId(value: string): DetachDocumentRequest; + static fromBinary(bytes: Uint8Array, options?: Partial): DeactivateClientRequest; - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): DetachDocumentRequest; - hasChangePack(): boolean; - clearChangePack(): DetachDocumentRequest; + static fromJson(jsonValue: JsonValue, options?: Partial): DeactivateClientRequest; - getRemoveIfNotAttached(): boolean; - setRemoveIfNotAttached(value: boolean): DetachDocumentRequest; + static fromJsonString(jsonString: string, options?: Partial): DeactivateClientRequest; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DetachDocumentRequest.AsObject; - static toObject(includeInstance: boolean, msg: DetachDocumentRequest): DetachDocumentRequest.AsObject; - static serializeBinaryToWriter(message: DetachDocumentRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DetachDocumentRequest; - static deserializeBinaryFromReader(message: DetachDocumentRequest, reader: jspb.BinaryReader): DetachDocumentRequest; + static equals(a: DeactivateClientRequest | PlainMessage | undefined, b: DeactivateClientRequest | PlainMessage | undefined): boolean; } -export namespace DetachDocumentRequest { - export type AsObject = { - clientId: string, - documentId: string, - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - removeIfNotAttached: boolean, - } -} +/** + * @generated from message yorkie.v1.DeactivateClientResponse + */ +export declare class DeactivateClientResponse extends Message { + constructor(data?: PartialMessage); -export class DetachDocumentResponse extends jspb.Message { - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): DetachDocumentResponse; - hasChangePack(): boolean; - clearChangePack(): DetachDocumentResponse; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): DetachDocumentResponse.AsObject; - static toObject(includeInstance: boolean, msg: DetachDocumentResponse): DetachDocumentResponse.AsObject; - static serializeBinaryToWriter(message: DetachDocumentResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): DetachDocumentResponse; - static deserializeBinaryFromReader(message: DetachDocumentResponse, reader: jspb.BinaryReader): DetachDocumentResponse; -} + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DeactivateClientResponse"; + static readonly fields: FieldList; -export namespace DetachDocumentResponse { - export type AsObject = { - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - } -} + static fromBinary(bytes: Uint8Array, options?: Partial): DeactivateClientResponse; -export class WatchDocumentRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): WatchDocumentRequest; + static fromJson(jsonValue: JsonValue, options?: Partial): DeactivateClientResponse; - getDocumentId(): string; - setDocumentId(value: string): WatchDocumentRequest; + static fromJsonString(jsonString: string, options?: Partial): DeactivateClientResponse; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): WatchDocumentRequest.AsObject; - static toObject(includeInstance: boolean, msg: WatchDocumentRequest): WatchDocumentRequest.AsObject; - static serializeBinaryToWriter(message: WatchDocumentRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): WatchDocumentRequest; - static deserializeBinaryFromReader(message: WatchDocumentRequest, reader: jspb.BinaryReader): WatchDocumentRequest; + static equals(a: DeactivateClientResponse | PlainMessage | undefined, b: DeactivateClientResponse | PlainMessage | undefined): boolean; } -export namespace WatchDocumentRequest { - export type AsObject = { - clientId: string, - documentId: string, - } -} +/** + * @generated from message yorkie.v1.AttachDocumentRequest + */ +export declare class AttachDocumentRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; -export class WatchDocumentResponse extends jspb.Message { - getInitialization(): WatchDocumentResponse.Initialization | undefined; - setInitialization(value?: WatchDocumentResponse.Initialization): WatchDocumentResponse; - hasInitialization(): boolean; - clearInitialization(): WatchDocumentResponse; - - getEvent(): yorkie_v1_resources_pb.DocEvent | undefined; - setEvent(value?: yorkie_v1_resources_pb.DocEvent): WatchDocumentResponse; - hasEvent(): boolean; - clearEvent(): WatchDocumentResponse; - - getBodyCase(): WatchDocumentResponse.BodyCase; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): WatchDocumentResponse.AsObject; - static toObject(includeInstance: boolean, msg: WatchDocumentResponse): WatchDocumentResponse.AsObject; - static serializeBinaryToWriter(message: WatchDocumentResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): WatchDocumentResponse; - static deserializeBinaryFromReader(message: WatchDocumentResponse, reader: jspb.BinaryReader): WatchDocumentResponse; -} + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 2; + */ + changePack?: ChangePack; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.AttachDocumentRequest"; + static readonly fields: FieldList; -export namespace WatchDocumentResponse { - export type AsObject = { - initialization?: WatchDocumentResponse.Initialization.AsObject, - event?: yorkie_v1_resources_pb.DocEvent.AsObject, - } - - export class Initialization extends jspb.Message { - getClientIdsList(): Array; - setClientIdsList(value: Array): Initialization; - clearClientIdsList(): Initialization; - addClientIds(value: string, index?: number): Initialization; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): Initialization.AsObject; - static toObject(includeInstance: boolean, msg: Initialization): Initialization.AsObject; - static serializeBinaryToWriter(message: Initialization, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): Initialization; - static deserializeBinaryFromReader(message: Initialization, reader: jspb.BinaryReader): Initialization; - } - - export namespace Initialization { - export type AsObject = { - clientIdsList: Array, - } - } - - - export enum BodyCase { - BODY_NOT_SET = 0, - INITIALIZATION = 1, - EVENT = 2, - } + static fromBinary(bytes: Uint8Array, options?: Partial): AttachDocumentRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): AttachDocumentRequest; + + static fromJsonString(jsonString: string, options?: Partial): AttachDocumentRequest; + + static equals(a: AttachDocumentRequest | PlainMessage | undefined, b: AttachDocumentRequest | PlainMessage | undefined): boolean; } -export class RemoveDocumentRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): RemoveDocumentRequest; +/** + * @generated from message yorkie.v1.AttachDocumentResponse + */ +export declare class AttachDocumentResponse extends Message { + /** + * @generated from field: string document_id = 1; + */ + documentId: string; + + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 2; + */ + changePack?: ChangePack; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.AttachDocumentResponse"; + static readonly fields: FieldList; - getDocumentId(): string; - setDocumentId(value: string): RemoveDocumentRequest; + static fromBinary(bytes: Uint8Array, options?: Partial): AttachDocumentResponse; - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): RemoveDocumentRequest; - hasChangePack(): boolean; - clearChangePack(): RemoveDocumentRequest; + static fromJson(jsonValue: JsonValue, options?: Partial): AttachDocumentResponse; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): RemoveDocumentRequest.AsObject; - static toObject(includeInstance: boolean, msg: RemoveDocumentRequest): RemoveDocumentRequest.AsObject; - static serializeBinaryToWriter(message: RemoveDocumentRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): RemoveDocumentRequest; - static deserializeBinaryFromReader(message: RemoveDocumentRequest, reader: jspb.BinaryReader): RemoveDocumentRequest; + static fromJsonString(jsonString: string, options?: Partial): AttachDocumentResponse; + + static equals(a: AttachDocumentResponse | PlainMessage | undefined, b: AttachDocumentResponse | PlainMessage | undefined): boolean; } -export namespace RemoveDocumentRequest { - export type AsObject = { - clientId: string, - documentId: string, - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - } +/** + * @generated from message yorkie.v1.DetachDocumentRequest + */ +export declare class DetachDocumentRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; + + /** + * @generated from field: string document_id = 2; + */ + documentId: string; + + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 3; + */ + changePack?: ChangePack; + + /** + * @generated from field: bool remove_if_not_attached = 4; + */ + removeIfNotAttached: boolean; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DetachDocumentRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): DetachDocumentRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): DetachDocumentRequest; + + static fromJsonString(jsonString: string, options?: Partial): DetachDocumentRequest; + + static equals(a: DetachDocumentRequest | PlainMessage | undefined, b: DetachDocumentRequest | PlainMessage | undefined): boolean; } -export class RemoveDocumentResponse extends jspb.Message { - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): RemoveDocumentResponse; - hasChangePack(): boolean; - clearChangePack(): RemoveDocumentResponse; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): RemoveDocumentResponse.AsObject; - static toObject(includeInstance: boolean, msg: RemoveDocumentResponse): RemoveDocumentResponse.AsObject; - static serializeBinaryToWriter(message: RemoveDocumentResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): RemoveDocumentResponse; - static deserializeBinaryFromReader(message: RemoveDocumentResponse, reader: jspb.BinaryReader): RemoveDocumentResponse; +/** + * @generated from message yorkie.v1.DetachDocumentResponse + */ +export declare class DetachDocumentResponse extends Message { + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 2; + */ + changePack?: ChangePack; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.DetachDocumentResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): DetachDocumentResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): DetachDocumentResponse; + + static fromJsonString(jsonString: string, options?: Partial): DetachDocumentResponse; + + static equals(a: DetachDocumentResponse | PlainMessage | undefined, b: DetachDocumentResponse | PlainMessage | undefined): boolean; } -export namespace RemoveDocumentResponse { - export type AsObject = { - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - } +/** + * @generated from message yorkie.v1.WatchDocumentRequest + */ +export declare class WatchDocumentRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; + + /** + * @generated from field: string document_id = 2; + */ + documentId: string; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.WatchDocumentRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): WatchDocumentRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): WatchDocumentRequest; + + static fromJsonString(jsonString: string, options?: Partial): WatchDocumentRequest; + + static equals(a: WatchDocumentRequest | PlainMessage | undefined, b: WatchDocumentRequest | PlainMessage | undefined): boolean; } -export class PushPullChangesRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): PushPullChangesRequest; +/** + * @generated from message yorkie.v1.WatchDocumentResponse + */ +export declare class WatchDocumentResponse extends Message { + /** + * @generated from oneof yorkie.v1.WatchDocumentResponse.body + */ + body: { + /** + * @generated from field: yorkie.v1.WatchDocumentResponse.Initialization initialization = 1; + */ + value: WatchDocumentResponse_Initialization; + case: "initialization"; + } | { + /** + * @generated from field: yorkie.v1.DocEvent event = 2; + */ + value: DocEvent; + case: "event"; + } | { case: undefined; value?: undefined }; - getDocumentId(): string; - setDocumentId(value: string): PushPullChangesRequest; + constructor(data?: PartialMessage); - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): PushPullChangesRequest; - hasChangePack(): boolean; - clearChangePack(): PushPullChangesRequest; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.WatchDocumentResponse"; + static readonly fields: FieldList; - getPushOnly(): boolean; - setPushOnly(value: boolean): PushPullChangesRequest; + static fromBinary(bytes: Uint8Array, options?: Partial): WatchDocumentResponse; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): PushPullChangesRequest.AsObject; - static toObject(includeInstance: boolean, msg: PushPullChangesRequest): PushPullChangesRequest.AsObject; - static serializeBinaryToWriter(message: PushPullChangesRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): PushPullChangesRequest; - static deserializeBinaryFromReader(message: PushPullChangesRequest, reader: jspb.BinaryReader): PushPullChangesRequest; + static fromJson(jsonValue: JsonValue, options?: Partial): WatchDocumentResponse; + + static fromJsonString(jsonString: string, options?: Partial): WatchDocumentResponse; + + static equals(a: WatchDocumentResponse | PlainMessage | undefined, b: WatchDocumentResponse | PlainMessage | undefined): boolean; } -export namespace PushPullChangesRequest { - export type AsObject = { - clientId: string, - documentId: string, - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - pushOnly: boolean, - } +/** + * @generated from message yorkie.v1.WatchDocumentResponse.Initialization + */ +export declare class WatchDocumentResponse_Initialization extends Message { + /** + * @generated from field: repeated string client_ids = 1; + */ + clientIds: string[]; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.WatchDocumentResponse.Initialization"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): WatchDocumentResponse_Initialization; + + static fromJson(jsonValue: JsonValue, options?: Partial): WatchDocumentResponse_Initialization; + + static fromJsonString(jsonString: string, options?: Partial): WatchDocumentResponse_Initialization; + + static equals(a: WatchDocumentResponse_Initialization | PlainMessage | undefined, b: WatchDocumentResponse_Initialization | PlainMessage | undefined): boolean; } -export class PushPullChangesResponse extends jspb.Message { - getChangePack(): yorkie_v1_resources_pb.ChangePack | undefined; - setChangePack(value?: yorkie_v1_resources_pb.ChangePack): PushPullChangesResponse; - hasChangePack(): boolean; - clearChangePack(): PushPullChangesResponse; - - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): PushPullChangesResponse.AsObject; - static toObject(includeInstance: boolean, msg: PushPullChangesResponse): PushPullChangesResponse.AsObject; - static serializeBinaryToWriter(message: PushPullChangesResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): PushPullChangesResponse; - static deserializeBinaryFromReader(message: PushPullChangesResponse, reader: jspb.BinaryReader): PushPullChangesResponse; +/** + * @generated from message yorkie.v1.RemoveDocumentRequest + */ +export declare class RemoveDocumentRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; + + /** + * @generated from field: string document_id = 2; + */ + documentId: string; + + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 3; + */ + changePack?: ChangePack; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.RemoveDocumentRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): RemoveDocumentRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): RemoveDocumentRequest; + + static fromJsonString(jsonString: string, options?: Partial): RemoveDocumentRequest; + + static equals(a: RemoveDocumentRequest | PlainMessage | undefined, b: RemoveDocumentRequest | PlainMessage | undefined): boolean; } -export namespace PushPullChangesResponse { - export type AsObject = { - changePack?: yorkie_v1_resources_pb.ChangePack.AsObject, - } +/** + * @generated from message yorkie.v1.RemoveDocumentResponse + */ +export declare class RemoveDocumentResponse extends Message { + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 1; + */ + changePack?: ChangePack; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.RemoveDocumentResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): RemoveDocumentResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): RemoveDocumentResponse; + + static fromJsonString(jsonString: string, options?: Partial): RemoveDocumentResponse; + + static equals(a: RemoveDocumentResponse | PlainMessage | undefined, b: RemoveDocumentResponse | PlainMessage | undefined): boolean; } -export class BroadcastRequest extends jspb.Message { - getClientId(): string; - setClientId(value: string): BroadcastRequest; +/** + * @generated from message yorkie.v1.PushPullChangesRequest + */ +export declare class PushPullChangesRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; + + /** + * @generated from field: string document_id = 2; + */ + documentId: string; + + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 3; + */ + changePack?: ChangePack; - getDocumentId(): string; - setDocumentId(value: string): BroadcastRequest; + /** + * @generated from field: bool push_only = 4; + */ + pushOnly: boolean; - getTopic(): string; - setTopic(value: string): BroadcastRequest; + constructor(data?: PartialMessage); - getPayload(): Uint8Array | string; - getPayload_asU8(): Uint8Array; - getPayload_asB64(): string; - setPayload(value: Uint8Array | string): BroadcastRequest; + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.PushPullChangesRequest"; + static readonly fields: FieldList; - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): BroadcastRequest.AsObject; - static toObject(includeInstance: boolean, msg: BroadcastRequest): BroadcastRequest.AsObject; - static serializeBinaryToWriter(message: BroadcastRequest, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): BroadcastRequest; - static deserializeBinaryFromReader(message: BroadcastRequest, reader: jspb.BinaryReader): BroadcastRequest; + static fromBinary(bytes: Uint8Array, options?: Partial): PushPullChangesRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): PushPullChangesRequest; + + static fromJsonString(jsonString: string, options?: Partial): PushPullChangesRequest; + + static equals(a: PushPullChangesRequest | PlainMessage | undefined, b: PushPullChangesRequest | PlainMessage | undefined): boolean; } -export namespace BroadcastRequest { - export type AsObject = { - clientId: string, - documentId: string, - topic: string, - payload: Uint8Array | string, - } +/** + * @generated from message yorkie.v1.PushPullChangesResponse + */ +export declare class PushPullChangesResponse extends Message { + /** + * @generated from field: yorkie.v1.ChangePack change_pack = 1; + */ + changePack?: ChangePack; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.PushPullChangesResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): PushPullChangesResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): PushPullChangesResponse; + + static fromJsonString(jsonString: string, options?: Partial): PushPullChangesResponse; + + static equals(a: PushPullChangesResponse | PlainMessage | undefined, b: PushPullChangesResponse | PlainMessage | undefined): boolean; } -export class BroadcastResponse extends jspb.Message { - serializeBinary(): Uint8Array; - toObject(includeInstance?: boolean): BroadcastResponse.AsObject; - static toObject(includeInstance: boolean, msg: BroadcastResponse): BroadcastResponse.AsObject; - static serializeBinaryToWriter(message: BroadcastResponse, writer: jspb.BinaryWriter): void; - static deserializeBinary(bytes: Uint8Array): BroadcastResponse; - static deserializeBinaryFromReader(message: BroadcastResponse, reader: jspb.BinaryReader): BroadcastResponse; +/** + * @generated from message yorkie.v1.BroadcastRequest + */ +export declare class BroadcastRequest extends Message { + /** + * @generated from field: string client_id = 1; + */ + clientId: string; + + /** + * @generated from field: string document_id = 2; + */ + documentId: string; + + /** + * @generated from field: string topic = 3; + */ + topic: string; + + /** + * @generated from field: bytes payload = 4; + */ + payload: Uint8Array; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.BroadcastRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): BroadcastRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): BroadcastRequest; + + static fromJsonString(jsonString: string, options?: Partial): BroadcastRequest; + + static equals(a: BroadcastRequest | PlainMessage | undefined, b: BroadcastRequest | PlainMessage | undefined): boolean; } -export namespace BroadcastResponse { - export type AsObject = { - } +/** + * @generated from message yorkie.v1.BroadcastResponse + */ +export declare class BroadcastResponse extends Message { + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "yorkie.v1.BroadcastResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): BroadcastResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): BroadcastResponse; + + static fromJsonString(jsonString: string, options?: Partial): BroadcastResponse; + + static equals(a: BroadcastResponse | PlainMessage | undefined, b: BroadcastResponse | PlainMessage | undefined): boolean; } diff --git a/src/api/yorkie/v1/yorkie_pb.js b/src/api/yorkie/v1/yorkie_pb.js index 553b34687..97b8ad6e8 100644 --- a/src/api/yorkie/v1/yorkie_pb.js +++ b/src/api/yorkie/v1/yorkie_pb.js @@ -1,3289 +1,226 @@ -// source: yorkie/v1/yorkie.proto -/** - * @fileoverview - * @enhanceable - * @suppress {missingRequire} reports error on implicit type usages. - * @suppress {messageConventions} JS Compiler reports an error if a variable or - * field starts with 'MSG_' and isn't a translatable message. - * @public - */ -// GENERATED CODE -- DO NOT EDIT! +// +// Copyright 2020 The Yorkie Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v1.6.0 with parameter "target=js+dts,js_import_style=legacy_commonjs" +// @generated from file src/api/yorkie/v1/yorkie.proto (package yorkie.v1, syntax proto3) /* eslint-disable */ // @ts-nocheck -var jspb = require('google-protobuf'); -var goog = jspb; -var global = - (typeof globalThis !== 'undefined' && globalThis) || - (typeof window !== 'undefined' && window) || - (typeof global !== 'undefined' && global) || - (typeof self !== 'undefined' && self) || - (function () { return this; }).call(null) || - Function('return this')(); - -var yorkie_v1_resources_pb = require('../../yorkie/v1/resources_pb.js'); -goog.object.extend(proto, yorkie_v1_resources_pb); -goog.exportSymbol('proto.yorkie.v1.ActivateClientRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.ActivateClientResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.AttachDocumentRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.AttachDocumentResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.BroadcastRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.BroadcastResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.DeactivateClientRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.DeactivateClientResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.DetachDocumentRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.DetachDocumentResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.PushPullChangesRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.PushPullChangesResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.RemoveDocumentRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.RemoveDocumentResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.WatchDocumentRequest', null, global); -goog.exportSymbol('proto.yorkie.v1.WatchDocumentResponse', null, global); -goog.exportSymbol('proto.yorkie.v1.WatchDocumentResponse.BodyCase', null, global); -goog.exportSymbol('proto.yorkie.v1.WatchDocumentResponse.Initialization', null, global); -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.ActivateClientRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.ActivateClientRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.ActivateClientRequest.displayName = 'proto.yorkie.v1.ActivateClientRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.ActivateClientResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.ActivateClientResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.ActivateClientResponse.displayName = 'proto.yorkie.v1.ActivateClientResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DeactivateClientRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DeactivateClientRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DeactivateClientRequest.displayName = 'proto.yorkie.v1.DeactivateClientRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DeactivateClientResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DeactivateClientResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DeactivateClientResponse.displayName = 'proto.yorkie.v1.DeactivateClientResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.AttachDocumentRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.AttachDocumentRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.AttachDocumentRequest.displayName = 'proto.yorkie.v1.AttachDocumentRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.AttachDocumentResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.AttachDocumentResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.AttachDocumentResponse.displayName = 'proto.yorkie.v1.AttachDocumentResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DetachDocumentRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DetachDocumentRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DetachDocumentRequest.displayName = 'proto.yorkie.v1.DetachDocumentRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.DetachDocumentResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.DetachDocumentResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.DetachDocumentResponse.displayName = 'proto.yorkie.v1.DetachDocumentResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.WatchDocumentRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.WatchDocumentRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.WatchDocumentRequest.displayName = 'proto.yorkie.v1.WatchDocumentRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.WatchDocumentResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, proto.yorkie.v1.WatchDocumentResponse.oneofGroups_); -}; -goog.inherits(proto.yorkie.v1.WatchDocumentResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.WatchDocumentResponse.displayName = 'proto.yorkie.v1.WatchDocumentResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, proto.yorkie.v1.WatchDocumentResponse.Initialization.repeatedFields_, null); -}; -goog.inherits(proto.yorkie.v1.WatchDocumentResponse.Initialization, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.WatchDocumentResponse.Initialization.displayName = 'proto.yorkie.v1.WatchDocumentResponse.Initialization'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.RemoveDocumentRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.RemoveDocumentRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.RemoveDocumentRequest.displayName = 'proto.yorkie.v1.RemoveDocumentRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.RemoveDocumentResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.RemoveDocumentResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.RemoveDocumentResponse.displayName = 'proto.yorkie.v1.RemoveDocumentResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.PushPullChangesRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.PushPullChangesRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.PushPullChangesRequest.displayName = 'proto.yorkie.v1.PushPullChangesRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.PushPullChangesResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.PushPullChangesResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.PushPullChangesResponse.displayName = 'proto.yorkie.v1.PushPullChangesResponse'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.BroadcastRequest = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.BroadcastRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.BroadcastRequest.displayName = 'proto.yorkie.v1.BroadcastRequest'; -} -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.yorkie.v1.BroadcastResponse = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.yorkie.v1.BroadcastResponse, jspb.Message); -if (goog.DEBUG && !COMPILED) { - /** - * @public - * @override - */ - proto.yorkie.v1.BroadcastResponse.displayName = 'proto.yorkie.v1.BroadcastResponse'; -} - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.ActivateClientRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.ActivateClientRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.ActivateClientRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ActivateClientRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientKey: jspb.Message.getFieldWithDefault(msg, 1, "") - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.ActivateClientRequest} - */ -proto.yorkie.v1.ActivateClientRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.ActivateClientRequest; - return proto.yorkie.v1.ActivateClientRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.ActivateClientRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.ActivateClientRequest} - */ -proto.yorkie.v1.ActivateClientRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientKey(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.ActivateClientRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.ActivateClientRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.ActivateClientRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ActivateClientRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientKey(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } -}; - - -/** - * optional string client_key = 1; - * @return {string} - */ -proto.yorkie.v1.ActivateClientRequest.prototype.getClientKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.ActivateClientRequest} returns this - */ -proto.yorkie.v1.ActivateClientRequest.prototype.setClientKey = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.ActivateClientResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.ActivateClientResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.ActivateClientResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ActivateClientResponse.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, "") - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.ActivateClientResponse} - */ -proto.yorkie.v1.ActivateClientResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.ActivateClientResponse; - return proto.yorkie.v1.ActivateClientResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.ActivateClientResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.ActivateClientResponse} - */ -proto.yorkie.v1.ActivateClientResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.ActivateClientResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.ActivateClientResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.ActivateClientResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.ActivateClientResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.ActivateClientResponse.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.ActivateClientResponse} returns this - */ -proto.yorkie.v1.ActivateClientResponse.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.DeactivateClientRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DeactivateClientRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DeactivateClientRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DeactivateClientRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, "") - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DeactivateClientRequest} - */ -proto.yorkie.v1.DeactivateClientRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DeactivateClientRequest; - return proto.yorkie.v1.DeactivateClientRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DeactivateClientRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DeactivateClientRequest} - */ -proto.yorkie.v1.DeactivateClientRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DeactivateClientRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DeactivateClientRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DeactivateClientRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DeactivateClientRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.DeactivateClientRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DeactivateClientRequest} returns this - */ -proto.yorkie.v1.DeactivateClientRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.DeactivateClientResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DeactivateClientResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DeactivateClientResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DeactivateClientResponse.toObject = function(includeInstance, msg) { - var f, obj = { - - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DeactivateClientResponse} - */ -proto.yorkie.v1.DeactivateClientResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DeactivateClientResponse; - return proto.yorkie.v1.DeactivateClientResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DeactivateClientResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DeactivateClientResponse} - */ -proto.yorkie.v1.DeactivateClientResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DeactivateClientResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DeactivateClientResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DeactivateClientResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DeactivateClientResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.AttachDocumentRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.AttachDocumentRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.AttachDocumentRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.AttachDocumentRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.AttachDocumentRequest} - */ -proto.yorkie.v1.AttachDocumentRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.AttachDocumentRequest; - return proto.yorkie.v1.AttachDocumentRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.AttachDocumentRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.AttachDocumentRequest} - */ -proto.yorkie.v1.AttachDocumentRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - case 2: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const { proto3 } = require("@bufbuild/protobuf"); +const { ChangePack, DocEvent } = require("./resources_pb.js"); /** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} + * @generated from message yorkie.v1.ActivateClientRequest */ -proto.yorkie.v1.AttachDocumentRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.AttachDocumentRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.AttachDocumentRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.AttachDocumentRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 2, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.AttachDocumentRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.AttachDocumentRequest} returns this - */ -proto.yorkie.v1.AttachDocumentRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional ChangePack change_pack = 2; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.AttachDocumentRequest.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.AttachDocumentRequest} returns this -*/ -proto.yorkie.v1.AttachDocumentRequest.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.AttachDocumentRequest} returns this - */ -proto.yorkie.v1.AttachDocumentRequest.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.AttachDocumentRequest.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.AttachDocumentResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.AttachDocumentResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.AttachDocumentResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.AttachDocumentResponse.toObject = function(includeInstance, msg) { - var f, obj = { - documentId: jspb.Message.getFieldWithDefault(msg, 1, ""), - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - +const ActivateClientRequest = proto3.makeMessageType( + "yorkie.v1.ActivateClientRequest", + () => [ + { no: 1, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ], +); /** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.AttachDocumentResponse} + * @generated from message yorkie.v1.ActivateClientResponse */ -proto.yorkie.v1.AttachDocumentResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.AttachDocumentResponse; - return proto.yorkie.v1.AttachDocumentResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.AttachDocumentResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.AttachDocumentResponse} - */ -proto.yorkie.v1.AttachDocumentResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentId(value); - break; - case 2: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - +const ActivateClientResponse = proto3.makeMessageType( + "yorkie.v1.ActivateClientResponse", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ], +); /** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} + * @generated from message yorkie.v1.DeactivateClientRequest */ -proto.yorkie.v1.AttachDocumentResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.AttachDocumentResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - +const DeactivateClientRequest = proto3.makeMessageType( + "yorkie.v1.DeactivateClientRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ], +); /** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.AttachDocumentResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages + * @generated from message yorkie.v1.DeactivateClientResponse */ -proto.yorkie.v1.AttachDocumentResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getDocumentId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 2, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } -}; - +const DeactivateClientResponse = proto3.makeMessageType( + "yorkie.v1.DeactivateClientResponse", + [], +); /** - * optional string document_id = 1; - * @return {string} + * @generated from message yorkie.v1.AttachDocumentRequest */ -proto.yorkie.v1.AttachDocumentResponse.prototype.getDocumentId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - +const AttachDocumentRequest = proto3.makeMessageType( + "yorkie.v1.AttachDocumentRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "change_pack", kind: "message", T: ChangePack }, + ], +); /** - * @param {string} value - * @return {!proto.yorkie.v1.AttachDocumentResponse} returns this + * @generated from message yorkie.v1.AttachDocumentResponse */ -proto.yorkie.v1.AttachDocumentResponse.prototype.setDocumentId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - +const AttachDocumentResponse = proto3.makeMessageType( + "yorkie.v1.AttachDocumentResponse", + () => [ + { no: 1, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "change_pack", kind: "message", T: ChangePack }, + ], +); /** - * optional ChangePack change_pack = 2; - * @return {?proto.yorkie.v1.ChangePack} + * @generated from message yorkie.v1.DetachDocumentRequest */ -proto.yorkie.v1.AttachDocumentResponse.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.AttachDocumentResponse} returns this -*/ -proto.yorkie.v1.AttachDocumentResponse.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - +const DetachDocumentRequest = proto3.makeMessageType( + "yorkie.v1.DetachDocumentRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "change_pack", kind: "message", T: ChangePack }, + { no: 4, name: "remove_if_not_attached", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + ], +); /** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.AttachDocumentResponse} returns this + * @generated from message yorkie.v1.DetachDocumentResponse */ -proto.yorkie.v1.AttachDocumentResponse.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - +const DetachDocumentResponse = proto3.makeMessageType( + "yorkie.v1.DetachDocumentResponse", + () => [ + { no: 2, name: "change_pack", kind: "message", T: ChangePack }, + ], +); /** - * Returns whether this field is set. - * @return {boolean} + * @generated from message yorkie.v1.WatchDocumentRequest */ -proto.yorkie.v1.AttachDocumentResponse.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 2) != null; -}; - - +const WatchDocumentRequest = proto3.makeMessageType( + "yorkie.v1.WatchDocumentRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ], +); - - -if (jspb.Message.GENERATE_TO_OBJECT) { /** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} + * @generated from message yorkie.v1.WatchDocumentResponse */ -proto.yorkie.v1.DetachDocumentRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DetachDocumentRequest.toObject(opt_includeInstance, this); -}; - +const WatchDocumentResponse = proto3.makeMessageType( + "yorkie.v1.WatchDocumentResponse", + () => [ + { no: 1, name: "initialization", kind: "message", T: WatchDocumentResponse_Initialization, oneof: "body" }, + { no: 2, name: "event", kind: "message", T: DocEvent, oneof: "body" }, + ], +); /** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DetachDocumentRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages + * @generated from message yorkie.v1.WatchDocumentResponse.Initialization */ -proto.yorkie.v1.DetachDocumentRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), - documentId: jspb.Message.getFieldWithDefault(msg, 2, ""), - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f), - removeIfNotAttached: jspb.Message.getBooleanFieldWithDefault(msg, 4, false) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - +const WatchDocumentResponse_Initialization = proto3.makeMessageType( + "yorkie.v1.WatchDocumentResponse.Initialization", + () => [ + { no: 1, name: "client_ids", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ], + {localName: "WatchDocumentResponse_Initialization"}, +); /** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DetachDocumentRequest} + * @generated from message yorkie.v1.RemoveDocumentRequest */ -proto.yorkie.v1.DetachDocumentRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DetachDocumentRequest; - return proto.yorkie.v1.DetachDocumentRequest.deserializeBinaryFromReader(msg, reader); -}; - +const RemoveDocumentRequest = proto3.makeMessageType( + "yorkie.v1.RemoveDocumentRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "change_pack", kind: "message", T: ChangePack }, + ], +); /** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DetachDocumentRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DetachDocumentRequest} + * @generated from message yorkie.v1.RemoveDocumentResponse */ -proto.yorkie.v1.DetachDocumentRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentId(value); - break; - case 3: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - case 4: - var value = /** @type {boolean} */ (reader.readBool()); - msg.setRemoveIfNotAttached(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - +const RemoveDocumentResponse = proto3.makeMessageType( + "yorkie.v1.RemoveDocumentResponse", + () => [ + { no: 1, name: "change_pack", kind: "message", T: ChangePack }, + ], +); /** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DetachDocumentRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; + * @generated from message yorkie.v1.PushPullChangesRequest + */ +const PushPullChangesRequest = proto3.makeMessageType( + "yorkie.v1.PushPullChangesRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "change_pack", kind: "message", T: ChangePack }, + { no: 4, name: "push_only", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, + ], +); + +/** + * @generated from message yorkie.v1.PushPullChangesResponse + */ +const PushPullChangesResponse = proto3.makeMessageType( + "yorkie.v1.PushPullChangesResponse", + () => [ + { no: 1, name: "change_pack", kind: "message", T: ChangePack }, + ], +); + +/** + * @generated from message yorkie.v1.BroadcastRequest + */ +const BroadcastRequest = proto3.makeMessageType( + "yorkie.v1.BroadcastRequest", + () => [ + { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "payload", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, + ], +); - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DetachDocumentRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DetachDocumentRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getDocumentId(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 3, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } - f = message.getRemoveIfNotAttached(); - if (f) { - writer.writeBool( - 4, - f - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DetachDocumentRequest} returns this - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string document_id = 2; - * @return {string} - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.getDocumentId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.DetachDocumentRequest} returns this - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.setDocumentId = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional ChangePack change_pack = 3; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.DetachDocumentRequest} returns this -*/ -proto.yorkie.v1.DetachDocumentRequest.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.DetachDocumentRequest} returns this - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional bool remove_if_not_attached = 4; - * @return {boolean} - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.getRemoveIfNotAttached = function() { - return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false)); -}; - - -/** - * @param {boolean} value - * @return {!proto.yorkie.v1.DetachDocumentRequest} returns this - */ -proto.yorkie.v1.DetachDocumentRequest.prototype.setRemoveIfNotAttached = function(value) { - return jspb.Message.setProto3BooleanField(this, 4, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.DetachDocumentResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.DetachDocumentResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.DetachDocumentResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DetachDocumentResponse.toObject = function(includeInstance, msg) { - var f, obj = { - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.DetachDocumentResponse} - */ -proto.yorkie.v1.DetachDocumentResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.DetachDocumentResponse; - return proto.yorkie.v1.DetachDocumentResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.DetachDocumentResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.DetachDocumentResponse} - */ -proto.yorkie.v1.DetachDocumentResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 2: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.DetachDocumentResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.DetachDocumentResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.DetachDocumentResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.DetachDocumentResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 2, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } -}; - - -/** - * optional ChangePack change_pack = 2; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.DetachDocumentResponse.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.DetachDocumentResponse} returns this -*/ -proto.yorkie.v1.DetachDocumentResponse.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 2, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.DetachDocumentResponse} returns this - */ -proto.yorkie.v1.DetachDocumentResponse.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.DetachDocumentResponse.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.WatchDocumentRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.WatchDocumentRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.WatchDocumentRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.WatchDocumentRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), - documentId: jspb.Message.getFieldWithDefault(msg, 2, "") - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.WatchDocumentRequest} - */ -proto.yorkie.v1.WatchDocumentRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.WatchDocumentRequest; - return proto.yorkie.v1.WatchDocumentRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.WatchDocumentRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.WatchDocumentRequest} - */ -proto.yorkie.v1.WatchDocumentRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentId(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.WatchDocumentRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.WatchDocumentRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.WatchDocumentRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.WatchDocumentRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getDocumentId(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.WatchDocumentRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.WatchDocumentRequest} returns this - */ -proto.yorkie.v1.WatchDocumentRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string document_id = 2; - * @return {string} - */ -proto.yorkie.v1.WatchDocumentRequest.prototype.getDocumentId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.WatchDocumentRequest} returns this - */ -proto.yorkie.v1.WatchDocumentRequest.prototype.setDocumentId = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - - -/** - * Oneof group definitions for this message. Each group defines the field - * numbers belonging to that group. When of these fields' value is set, all - * other fields in the group are cleared. During deserialization, if multiple - * fields are encountered for a group, only the last value seen will be kept. - * @private {!Array>} - * @const - */ -proto.yorkie.v1.WatchDocumentResponse.oneofGroups_ = [[1,2]]; - -/** - * @enum {number} - */ -proto.yorkie.v1.WatchDocumentResponse.BodyCase = { - BODY_NOT_SET: 0, - INITIALIZATION: 1, - EVENT: 2 -}; - -/** - * @return {proto.yorkie.v1.WatchDocumentResponse.BodyCase} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.getBodyCase = function() { - return /** @type {proto.yorkie.v1.WatchDocumentResponse.BodyCase} */(jspb.Message.computeOneofCase(this, proto.yorkie.v1.WatchDocumentResponse.oneofGroups_[0])); -}; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.WatchDocumentResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.WatchDocumentResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.WatchDocumentResponse.toObject = function(includeInstance, msg) { - var f, obj = { - initialization: (f = msg.getInitialization()) && proto.yorkie.v1.WatchDocumentResponse.Initialization.toObject(includeInstance, f), - event: (f = msg.getEvent()) && yorkie_v1_resources_pb.DocEvent.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.WatchDocumentResponse} - */ -proto.yorkie.v1.WatchDocumentResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.WatchDocumentResponse; - return proto.yorkie.v1.WatchDocumentResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.WatchDocumentResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.WatchDocumentResponse} - */ -proto.yorkie.v1.WatchDocumentResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.yorkie.v1.WatchDocumentResponse.Initialization; - reader.readMessage(value,proto.yorkie.v1.WatchDocumentResponse.Initialization.deserializeBinaryFromReader); - msg.setInitialization(value); - break; - case 2: - var value = new yorkie_v1_resources_pb.DocEvent; - reader.readMessage(value,yorkie_v1_resources_pb.DocEvent.deserializeBinaryFromReader); - msg.setEvent(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.WatchDocumentResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.WatchDocumentResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.WatchDocumentResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getInitialization(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.yorkie.v1.WatchDocumentResponse.Initialization.serializeBinaryToWriter - ); - } - f = message.getEvent(); - if (f != null) { - writer.writeMessage( - 2, - f, - yorkie_v1_resources_pb.DocEvent.serializeBinaryToWriter - ); - } -}; - - - -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.repeatedFields_ = [1]; - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.WatchDocumentResponse.Initialization.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.WatchDocumentResponse.Initialization} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.toObject = function(includeInstance, msg) { - var f, obj = { - clientIdsList: (f = jspb.Message.getRepeatedField(msg, 1)) == null ? undefined : f - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.WatchDocumentResponse.Initialization} - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.WatchDocumentResponse.Initialization; - return proto.yorkie.v1.WatchDocumentResponse.Initialization.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.WatchDocumentResponse.Initialization} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.WatchDocumentResponse.Initialization} - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.addClientIds(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.WatchDocumentResponse.Initialization.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.WatchDocumentResponse.Initialization} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientIdsList(); - if (f.length > 0) { - writer.writeRepeatedString( - 1, - f - ); - } -}; - - -/** - * repeated string client_ids = 1; - * @return {!Array} - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.prototype.getClientIdsList = function() { - return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); -}; - - -/** - * @param {!Array} value - * @return {!proto.yorkie.v1.WatchDocumentResponse.Initialization} returns this - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.prototype.setClientIdsList = function(value) { - return jspb.Message.setField(this, 1, value || []); -}; - - -/** - * @param {string} value - * @param {number=} opt_index - * @return {!proto.yorkie.v1.WatchDocumentResponse.Initialization} returns this - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.prototype.addClientIds = function(value, opt_index) { - return jspb.Message.addToRepeatedField(this, 1, value, opt_index); -}; - - -/** - * Clears the list making it empty but non-null. - * @return {!proto.yorkie.v1.WatchDocumentResponse.Initialization} returns this - */ -proto.yorkie.v1.WatchDocumentResponse.Initialization.prototype.clearClientIdsList = function() { - return this.setClientIdsList([]); -}; - - -/** - * optional Initialization initialization = 1; - * @return {?proto.yorkie.v1.WatchDocumentResponse.Initialization} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.getInitialization = function() { - return /** @type{?proto.yorkie.v1.WatchDocumentResponse.Initialization} */ ( - jspb.Message.getWrapperField(this, proto.yorkie.v1.WatchDocumentResponse.Initialization, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.WatchDocumentResponse.Initialization|undefined} value - * @return {!proto.yorkie.v1.WatchDocumentResponse} returns this -*/ -proto.yorkie.v1.WatchDocumentResponse.prototype.setInitialization = function(value) { - return jspb.Message.setOneofWrapperField(this, 1, proto.yorkie.v1.WatchDocumentResponse.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.WatchDocumentResponse} returns this - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.clearInitialization = function() { - return this.setInitialization(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.hasInitialization = function() { - return jspb.Message.getField(this, 1) != null; -}; - - -/** - * optional DocEvent event = 2; - * @return {?proto.yorkie.v1.DocEvent} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.getEvent = function() { - return /** @type{?proto.yorkie.v1.DocEvent} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.DocEvent, 2)); -}; - - -/** - * @param {?proto.yorkie.v1.DocEvent|undefined} value - * @return {!proto.yorkie.v1.WatchDocumentResponse} returns this -*/ -proto.yorkie.v1.WatchDocumentResponse.prototype.setEvent = function(value) { - return jspb.Message.setOneofWrapperField(this, 2, proto.yorkie.v1.WatchDocumentResponse.oneofGroups_[0], value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.WatchDocumentResponse} returns this - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.clearEvent = function() { - return this.setEvent(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.WatchDocumentResponse.prototype.hasEvent = function() { - return jspb.Message.getField(this, 2) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.RemoveDocumentRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.RemoveDocumentRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RemoveDocumentRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), - documentId: jspb.Message.getFieldWithDefault(msg, 2, ""), - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.RemoveDocumentRequest} - */ -proto.yorkie.v1.RemoveDocumentRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.RemoveDocumentRequest; - return proto.yorkie.v1.RemoveDocumentRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.RemoveDocumentRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.RemoveDocumentRequest} - */ -proto.yorkie.v1.RemoveDocumentRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentId(value); - break; - case 3: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.RemoveDocumentRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.RemoveDocumentRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RemoveDocumentRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getDocumentId(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 3, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.RemoveDocumentRequest} returns this - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string document_id = 2; - * @return {string} - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.getDocumentId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.RemoveDocumentRequest} returns this - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.setDocumentId = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional ChangePack change_pack = 3; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.RemoveDocumentRequest} returns this -*/ -proto.yorkie.v1.RemoveDocumentRequest.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.RemoveDocumentRequest} returns this - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.RemoveDocumentRequest.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 3) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.RemoveDocumentResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.RemoveDocumentResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.RemoveDocumentResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RemoveDocumentResponse.toObject = function(includeInstance, msg) { - var f, obj = { - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.RemoveDocumentResponse} - */ -proto.yorkie.v1.RemoveDocumentResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.RemoveDocumentResponse; - return proto.yorkie.v1.RemoveDocumentResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.RemoveDocumentResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.RemoveDocumentResponse} - */ -proto.yorkie.v1.RemoveDocumentResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.RemoveDocumentResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.RemoveDocumentResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.RemoveDocumentResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.RemoveDocumentResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 1, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } -}; - - -/** - * optional ChangePack change_pack = 1; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.RemoveDocumentResponse.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.RemoveDocumentResponse} returns this -*/ -proto.yorkie.v1.RemoveDocumentResponse.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.RemoveDocumentResponse} returns this - */ -proto.yorkie.v1.RemoveDocumentResponse.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.RemoveDocumentResponse.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 1) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.PushPullChangesRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.PushPullChangesRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.PushPullChangesRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), - documentId: jspb.Message.getFieldWithDefault(msg, 2, ""), - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f), - pushOnly: jspb.Message.getBooleanFieldWithDefault(msg, 4, false) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.PushPullChangesRequest} - */ -proto.yorkie.v1.PushPullChangesRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.PushPullChangesRequest; - return proto.yorkie.v1.PushPullChangesRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.PushPullChangesRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.PushPullChangesRequest} - */ -proto.yorkie.v1.PushPullChangesRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentId(value); - break; - case 3: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - case 4: - var value = /** @type {boolean} */ (reader.readBool()); - msg.setPushOnly(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.PushPullChangesRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.PushPullChangesRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.PushPullChangesRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getDocumentId(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 3, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } - f = message.getPushOnly(); - if (f) { - writer.writeBool( - 4, - f - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.PushPullChangesRequest} returns this - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string document_id = 2; - * @return {string} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.getDocumentId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.PushPullChangesRequest} returns this - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.setDocumentId = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional ChangePack change_pack = 3; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 3)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.PushPullChangesRequest} returns this -*/ -proto.yorkie.v1.PushPullChangesRequest.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 3, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.PushPullChangesRequest} returns this - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 3) != null; -}; - - -/** - * optional bool push_only = 4; - * @return {boolean} - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.getPushOnly = function() { - return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false)); -}; - - -/** - * @param {boolean} value - * @return {!proto.yorkie.v1.PushPullChangesRequest} returns this - */ -proto.yorkie.v1.PushPullChangesRequest.prototype.setPushOnly = function(value) { - return jspb.Message.setProto3BooleanField(this, 4, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.PushPullChangesResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.PushPullChangesResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.PushPullChangesResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.PushPullChangesResponse.toObject = function(includeInstance, msg) { - var f, obj = { - changePack: (f = msg.getChangePack()) && yorkie_v1_resources_pb.ChangePack.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.PushPullChangesResponse} - */ -proto.yorkie.v1.PushPullChangesResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.PushPullChangesResponse; - return proto.yorkie.v1.PushPullChangesResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.PushPullChangesResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.PushPullChangesResponse} - */ -proto.yorkie.v1.PushPullChangesResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new yorkie_v1_resources_pb.ChangePack; - reader.readMessage(value,yorkie_v1_resources_pb.ChangePack.deserializeBinaryFromReader); - msg.setChangePack(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.PushPullChangesResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.PushPullChangesResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.PushPullChangesResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.PushPullChangesResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getChangePack(); - if (f != null) { - writer.writeMessage( - 1, - f, - yorkie_v1_resources_pb.ChangePack.serializeBinaryToWriter - ); - } -}; - - -/** - * optional ChangePack change_pack = 1; - * @return {?proto.yorkie.v1.ChangePack} - */ -proto.yorkie.v1.PushPullChangesResponse.prototype.getChangePack = function() { - return /** @type{?proto.yorkie.v1.ChangePack} */ ( - jspb.Message.getWrapperField(this, yorkie_v1_resources_pb.ChangePack, 1)); -}; - - -/** - * @param {?proto.yorkie.v1.ChangePack|undefined} value - * @return {!proto.yorkie.v1.PushPullChangesResponse} returns this -*/ -proto.yorkie.v1.PushPullChangesResponse.prototype.setChangePack = function(value) { - return jspb.Message.setWrapperField(this, 1, value); -}; - - -/** - * Clears the message field making it undefined. - * @return {!proto.yorkie.v1.PushPullChangesResponse} returns this - */ -proto.yorkie.v1.PushPullChangesResponse.prototype.clearChangePack = function() { - return this.setChangePack(undefined); -}; - - -/** - * Returns whether this field is set. - * @return {boolean} - */ -proto.yorkie.v1.PushPullChangesResponse.prototype.hasChangePack = function() { - return jspb.Message.getField(this, 1) != null; -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.BroadcastRequest.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.BroadcastRequest.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.BroadcastRequest} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.BroadcastRequest.toObject = function(includeInstance, msg) { - var f, obj = { - clientId: jspb.Message.getFieldWithDefault(msg, 1, ""), - documentId: jspb.Message.getFieldWithDefault(msg, 2, ""), - topic: jspb.Message.getFieldWithDefault(msg, 3, ""), - payload: msg.getPayload_asB64() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.BroadcastRequest} - */ -proto.yorkie.v1.BroadcastRequest.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.BroadcastRequest; - return proto.yorkie.v1.BroadcastRequest.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.BroadcastRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.BroadcastRequest} - */ -proto.yorkie.v1.BroadcastRequest.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setClientId(value); - break; - case 2: - var value = /** @type {string} */ (reader.readString()); - msg.setDocumentId(value); - break; - case 3: - var value = /** @type {string} */ (reader.readString()); - msg.setTopic(value); - break; - case 4: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setPayload(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.BroadcastRequest.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.BroadcastRequest.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.BroadcastRequest} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.BroadcastRequest.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getClientId(); - if (f.length > 0) { - writer.writeString( - 1, - f - ); - } - f = message.getDocumentId(); - if (f.length > 0) { - writer.writeString( - 2, - f - ); - } - f = message.getTopic(); - if (f.length > 0) { - writer.writeString( - 3, - f - ); - } - f = message.getPayload_asU8(); - if (f.length > 0) { - writer.writeBytes( - 4, - f - ); - } -}; - - -/** - * optional string client_id = 1; - * @return {string} - */ -proto.yorkie.v1.BroadcastRequest.prototype.getClientId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.BroadcastRequest} returns this - */ -proto.yorkie.v1.BroadcastRequest.prototype.setClientId = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); -}; - - -/** - * optional string document_id = 2; - * @return {string} - */ -proto.yorkie.v1.BroadcastRequest.prototype.getDocumentId = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.BroadcastRequest} returns this - */ -proto.yorkie.v1.BroadcastRequest.prototype.setDocumentId = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); -}; - - -/** - * optional string topic = 3; - * @return {string} - */ -proto.yorkie.v1.BroadcastRequest.prototype.getTopic = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); -}; - - -/** - * @param {string} value - * @return {!proto.yorkie.v1.BroadcastRequest} returns this - */ -proto.yorkie.v1.BroadcastRequest.prototype.setTopic = function(value) { - return jspb.Message.setProto3StringField(this, 3, value); -}; - - -/** - * optional bytes payload = 4; - * @return {string} - */ -proto.yorkie.v1.BroadcastRequest.prototype.getPayload = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 4, "")); -}; - - -/** - * optional bytes payload = 4; - * This is a type-conversion wrapper around `getPayload()` - * @return {string} - */ -proto.yorkie.v1.BroadcastRequest.prototype.getPayload_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getPayload())); -}; - - -/** - * optional bytes payload = 4; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getPayload()` - * @return {!Uint8Array} - */ -proto.yorkie.v1.BroadcastRequest.prototype.getPayload_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getPayload())); -}; - - -/** - * @param {!(string|Uint8Array)} value - * @return {!proto.yorkie.v1.BroadcastRequest} returns this - */ -proto.yorkie.v1.BroadcastRequest.prototype.setPayload = function(value) { - return jspb.Message.setProto3BytesField(this, 4, value); -}; - - - - - -if (jspb.Message.GENERATE_TO_OBJECT) { -/** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} - */ -proto.yorkie.v1.BroadcastResponse.prototype.toObject = function(opt_includeInstance) { - return proto.yorkie.v1.BroadcastResponse.toObject(opt_includeInstance, this); -}; - - -/** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.yorkie.v1.BroadcastResponse} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.BroadcastResponse.toObject = function(includeInstance, msg) { - var f, obj = { - - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.yorkie.v1.BroadcastResponse} - */ -proto.yorkie.v1.BroadcastResponse.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.yorkie.v1.BroadcastResponse; - return proto.yorkie.v1.BroadcastResponse.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.yorkie.v1.BroadcastResponse} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.yorkie.v1.BroadcastResponse} - */ -proto.yorkie.v1.BroadcastResponse.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - default: - reader.skipField(); - break; - } - } - return msg; -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.yorkie.v1.BroadcastResponse.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.yorkie.v1.BroadcastResponse.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); -}; - - -/** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.yorkie.v1.BroadcastResponse} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages - */ -proto.yorkie.v1.BroadcastResponse.serializeBinaryToWriter = function(message, writer) { - var f = undefined; -}; +/** + * @generated from message yorkie.v1.BroadcastResponse + */ +const BroadcastResponse = proto3.makeMessageType( + "yorkie.v1.BroadcastResponse", + [], +); -goog.object.extend(exports, proto.yorkie.v1); +exports.ActivateClientRequest = ActivateClientRequest; +exports.ActivateClientResponse = ActivateClientResponse; +exports.DeactivateClientRequest = DeactivateClientRequest; +exports.DeactivateClientResponse = DeactivateClientResponse; +exports.AttachDocumentRequest = AttachDocumentRequest; +exports.AttachDocumentResponse = AttachDocumentResponse; +exports.DetachDocumentRequest = DetachDocumentRequest; +exports.DetachDocumentResponse = DetachDocumentResponse; +exports.WatchDocumentRequest = WatchDocumentRequest; +exports.WatchDocumentResponse = WatchDocumentResponse; +exports.WatchDocumentResponse_Initialization = WatchDocumentResponse_Initialization; +exports.RemoveDocumentRequest = RemoveDocumentRequest; +exports.RemoveDocumentResponse = RemoveDocumentResponse; +exports.PushPullChangesRequest = PushPullChangesRequest; +exports.PushPullChangesResponse = PushPullChangesResponse; +exports.BroadcastRequest = BroadcastRequest; +exports.BroadcastResponse = BroadcastResponse; diff --git a/src/client/attachment.ts b/src/client/attachment.ts index 1eef50694..12cc58228 100644 --- a/src/client/attachment.ts +++ b/src/client/attachment.ts @@ -20,6 +20,7 @@ export class Attachment { watchStream?: WatchStream; watchLoopTimerID?: ReturnType; + watchAbortController?: AbortController; constructor( reconnectStreamDelay: number, @@ -85,12 +86,22 @@ export class Attachment { this.watchLoopTimerID = undefined; } - const onDisconnect = () => { - this.watchStream = undefined; - this.watchLoopTimerID = setTimeout(doLoop, this.reconnectStreamDelay); - }; - - this.watchStream = await watchStreamCreator(onDisconnect); + try { + [this.watchStream, this.watchAbortController] = + await watchStreamCreator(() => { + this.watchStream = undefined; + this.watchAbortController = undefined; + this.watchLoopTimerID = setTimeout( + doLoop, + this.reconnectStreamDelay, + ); + }); + } catch (err) { + // TODO(hackerwins): For now, if the creation of the watch stream fails, + // it is considered normal and the watch loop is executed again after a + // certain period of time. + // In the future, we need to find a better way to handle this. + } }; await doLoop(); @@ -100,9 +111,10 @@ export class Attachment { * `cancelWatchStream` cancels the watch stream. */ public cancelWatchStream(): void { - if (this.watchStream) { - this.watchStream.cancel(); + if (this.watchStream && this.watchAbortController) { + this.watchAbortController.abort(); this.watchStream = undefined; + this.watchAbortController = undefined; } clearTimeout(this.watchLoopTimerID); this.watchLoopTimerID = undefined; diff --git a/src/client/auth_interceptor.ts b/src/client/auth_interceptor.ts index b536afc90..81b41c029 100644 --- a/src/client/auth_interceptor.ts +++ b/src/client/auth_interceptor.ts @@ -14,60 +14,23 @@ * limitations under the License. */ -/** - * `AuthUnaryInterceptor` is a unary interceptor to add the Authorization header for each - * request. - */ -export class AuthUnaryInterceptor { - private apiKey?: string; - private token?: string; - - constructor(apiKey?: string, token?: string) { - this.apiKey = apiKey; - this.token = token; - } - - /** - * `intercept` intercepts the request and adds the token to the metadata. - */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - public intercept(request: any, invoker: any): any { - const metadata = request.getMetadata(); - if (this.apiKey) { - metadata['x-api-key'] = this.apiKey; - } - if (this.token) { - metadata['authorization'] = this.token; - } - return invoker(request); - } -} +import { Interceptor } from '@connectrpc/connect'; /** - * `AuthStreamInterceptor` is a stream interceptor to add the Authorization header for each + * `createAuthInterceptor` creates an interceptor to add the Authorization header for each * request. */ -export class AuthStreamInterceptor { - private apiKey?: string; - private token?: string; - - constructor(apiKey?: string, token?: string) { - this.apiKey = apiKey; - this.token = token; - } - - /** - * `intercept` intercepts the request and adds the token to the metadata. - */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - public intercept(request: any, invoker: any): any { - const metadata = request.getMetadata(); - if (this.apiKey) { - metadata['x-api-key'] = this.apiKey; +export function createAuthInterceptor( + apiKey?: string, + token?: string, +): Interceptor { + return (next) => async (req) => { + if (apiKey) { + req.header.set('x-api-key', apiKey); } - if (this.token) { - metadata['authorization'] = this.token; + if (token) { + req.header.set('authorization', token); } - return invoker(request); - } + return await next(req); + }; } diff --git a/src/client/client.ts b/src/client/client.ts index 71a69c57a..87e784cc0 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -24,19 +24,12 @@ import { CompleteFn, NextFn, } from '@yorkie-js-sdk/src/util/observable'; -import { - ActivateClientRequest, - DeactivateClientRequest, - AttachDocumentRequest, - DetachDocumentRequest, - PushPullChangesRequest, - RemoveDocumentRequest, - WatchDocumentRequest, - WatchDocumentResponse, -} from '@yorkie-js-sdk/src/api/yorkie/v1/yorkie_pb'; +import { createPromiseClient, PromiseClient } from '@connectrpc/connect'; +import { createGrpcWebTransport } from '@connectrpc/connect-web'; +import { YorkieService } from '../api/yorkie/v1/yorkie_connect'; +import { WatchDocumentResponse } from '@yorkie-js-sdk/src/api/yorkie/v1/yorkie_pb'; import { DocEventType as PbDocEventType } from '@yorkie-js-sdk/src/api/yorkie/v1/resources_pb'; import { converter } from '@yorkie-js-sdk/src/api/converter'; -import { YorkieServiceClient as RPCClient } from '@yorkie-js-sdk/src/api/yorkie/v1/yorkie_grpc_web_pb'; import { Code, YorkieError } from '@yorkie-js-sdk/src/util/error'; import { logger } from '@yorkie-js-sdk/src/util/logger'; import { uuid } from '@yorkie-js-sdk/src/util/uuid'; @@ -46,14 +39,8 @@ import { DocumentKey, DocumentStatus, } from '@yorkie-js-sdk/src/document/document'; -import { - AuthUnaryInterceptor, - AuthStreamInterceptor, -} from '@yorkie-js-sdk/src/client/auth_interceptor'; -import { - MetricUnaryInterceptor, - MetricStreamInterceptor, -} from '@yorkie-js-sdk/src/client/metric_interceptor'; +import { createAuthInterceptor } from '@yorkie-js-sdk/src/client/auth_interceptor'; +import { createMetricInterceptor } from '@yorkie-js-sdk/src/client/metric_interceptor'; import { Indexable, DocEventType } from '@yorkie-js-sdk/src/document/document'; /** @@ -309,7 +296,7 @@ export class Client implements Observable { private reconnectStreamDelay: number; private retrySyncLoopDelay: number; - private rpcClient: RPCClient; + private rpcClient: PromiseClient; private eventStream: Observable; private eventStreamObserver!: Observer; @@ -333,21 +320,19 @@ export class Client implements Observable { this.retrySyncLoopDelay = opts.retrySyncLoopDelay || DefaultClientOptions.retrySyncLoopDelay; - const rpcOpts = { - unaryInterceptors: [new MetricUnaryInterceptor()], - streamInterceptors: [new MetricStreamInterceptor()], - }; - - if (opts.apiKey || opts.token) { - rpcOpts.unaryInterceptors.push( - new AuthUnaryInterceptor(opts.apiKey, opts.token), - ); - rpcOpts.streamInterceptors.push( - new AuthStreamInterceptor(opts.apiKey, opts.token), - ); - } + // Here we make the client itself, combining the service + // definition with the transport. + this.rpcClient = createPromiseClient( + YorkieService, + createGrpcWebTransport({ + baseUrl: rpcAddr, + interceptors: [ + createAuthInterceptor(opts.apiKey, opts.token), + createMetricInterceptor(), + ], + }), + ); - this.rpcClient = new RPCClient(rpcAddr, null, rpcOpts); this.eventStream = createObservable((observer) => { this.eventStreamObserver = observer; }); @@ -363,34 +348,29 @@ export class Client implements Observable { return Promise.resolve(); } - return new Promise((resolve, reject) => { - const req = new ActivateClientRequest(); - req.setClientKey(this.key); - - this.rpcClient.activateClient( - req, - { 'x-shard-key': this.apiKey }, - async (err, res) => { - if (err) { - logger.error(`[AC] c:"${this.getKey()}" err :`, err); - reject(err); - return; - } - - this.id = res.getClientId(); - this.status = ClientStatus.Activated; - this.runSyncLoop(); + return this.rpcClient + .activateClient( + { + clientKey: this.key, + }, + { headers: { 'x-shard-key': this.apiKey } }, + ) + .then((res) => { + this.id = res.clientId; + this.status = ClientStatus.Activated; + this.runSyncLoop(); - this.eventStreamObserver.next({ - type: ClientEventType.StatusChanged, - value: this.status, - }); + this.eventStreamObserver.next({ + type: ClientEventType.StatusChanged, + value: this.status, + }); - logger.info(`[AC] c:"${this.getKey()}" activated, id:"${this.id}"`); - resolve(); - }, - ); - }); + logger.info(`[AC] c:"${this.getKey()}" activated, id:"${this.id}"`); + }) + .catch((err) => { + logger.error(`[AC] c:"${this.getKey()}" err :`, err); + throw err; + }); } /** @@ -405,31 +385,26 @@ export class Client implements Observable { this.detachInternal(key); } - return new Promise((resolve, reject) => { - const req = new DeactivateClientRequest(); - req.setClientId(this.id!); - - this.rpcClient.deactivateClient( - req, - { 'x-shard-key': this.apiKey }, - (err) => { - if (err) { - logger.error(`[DC] c:"${this.getKey()}" err :`, err); - reject(err); - return; - } - - this.status = ClientStatus.Deactivated; - this.eventStreamObserver.next({ - type: ClientEventType.StatusChanged, - value: this.status, - }); - - logger.info(`[DC] c"${this.getKey()}" deactivated`); - resolve(); + return this.rpcClient + .deactivateClient( + { + clientId: this.id!, }, - ); - }); + { headers: { 'x-shard-key': this.apiKey } }, + ) + .then(() => { + this.status = ClientStatus.Deactivated; + this.eventStreamObserver.next({ + type: ClientEventType.StatusChanged, + value: this.status, + }); + + logger.info(`[DC] c"${this.getKey()}" deactivated`); + }) + .catch((err) => { + logger.error(`[DC] c:"${this.getKey()}" err :`, err); + throw err; + }); } /** @@ -457,45 +432,45 @@ export class Client implements Observable { const isRealtimeSync = options.isRealtimeSync ?? true; - return new Promise((resolve, reject) => { - const req = new AttachDocumentRequest(); - req.setClientId(this.id!); - req.setChangePack(converter.toChangePack(doc.createChangePack())); - - this.rpcClient.attachDocument( - req, - { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, - async (err, res) => { - if (err) { - logger.error(`[AD] c:"${this.getKey()}" err :`, err); - reject(err); - return; - } + return this.rpcClient + .attachDocument( + { + clientId: this.id!, + changePack: converter.toChangePack(doc.createChangePack()), + }, + { + headers: { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, + }, + ) + .then(async (res) => { + const pack = converter.fromChangePack

(res.changePack!); + doc.applyChangePack(pack); + if (doc.getStatus() === DocumentStatus.Removed) { + return doc; + } - const pack = converter.fromChangePack

(res.getChangePack()!); - doc.applyChangePack(pack); - if (doc.getStatus() !== DocumentStatus.Removed) { - doc.setStatus(DocumentStatus.Attached); - this.attachmentMap.set( - doc.getKey(), - new Attachment( - this.reconnectStreamDelay, - doc, - res.getDocumentId(), - isRealtimeSync, - ), - ); - - if (isRealtimeSync) { - await this.runWatchLoop(doc.getKey()); - } - } + doc.setStatus(DocumentStatus.Attached); + this.attachmentMap.set( + doc.getKey(), + new Attachment( + this.reconnectStreamDelay, + doc, + res.documentId, + isRealtimeSync, + ), + ); - logger.info(`[AD] c:"${this.getKey()}" attaches d:"${doc.getKey()}"`); - resolve(doc); - }, - ); - }); + if (isRealtimeSync) { + await this.runWatchLoop(doc.getKey()); + } + + logger.info(`[AD] c:"${this.getKey()}" attaches d:"${doc.getKey()}"`); + return doc; + }) + .catch((err) => { + logger.error(`[AD] c:"${this.getKey()}" err :`, err); + throw err; + }); } /** @@ -524,35 +499,33 @@ export class Client implements Observable { } doc.update((_, p) => p.clear()); - return new Promise((resolve, reject) => { - const req = new DetachDocumentRequest(); - req.setClientId(this.id!); - req.setDocumentId(attachment.docID); - req.setChangePack(converter.toChangePack(doc.createChangePack())); - req.setRemoveIfNotAttached(options.removeIfNotAttached ?? false); - - this.rpcClient.detachDocument( - req, - { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, - async (err, res) => { - if (err) { - logger.error(`[DD] c:"${this.getKey()}" err :`, err); - reject(err); - return; - } - - const pack = converter.fromChangePack

(res.getChangePack()!); - doc.applyChangePack(pack); - if (doc.getStatus() !== DocumentStatus.Removed) { - doc.setStatus(DocumentStatus.Detached); - } - this.detachInternal(doc.getKey()); - - logger.info(`[DD] c:"${this.getKey()}" detaches d:"${doc.getKey()}"`); - resolve(doc); + return this.rpcClient + .detachDocument( + { + clientId: this.id!, + documentId: attachment.docID, + changePack: converter.toChangePack(doc.createChangePack()), + removeIfNotAttached: options.removeIfNotAttached ?? false, }, - ); - }); + { + headers: { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, + }, + ) + .then((res) => { + const pack = converter.fromChangePack

(res.changePack!); + doc.applyChangePack(pack); + if (doc.getStatus() !== DocumentStatus.Removed) { + doc.setStatus(DocumentStatus.Detached); + } + this.detachInternal(doc.getKey()); + + logger.info(`[DD] c:"${this.getKey()}" detaches d:"${doc.getKey()}"`); + return doc; + }) + .catch((err) => { + logger.error(`[DD] c:"${this.getKey()}" err :`, err); + throw err; + }); } /** @@ -707,36 +680,31 @@ export class Client implements Observable { ); } doc.setActor(this.id!); - return new Promise((resolve, reject) => { - const req = new RemoveDocumentRequest(); - req.setClientId(this.id!); - req.setDocumentId(attachment.docID); - const pbChangePack = converter.toChangePack(doc.createChangePack()); - pbChangePack.setIsRemoved(true); - req.setChangePack(pbChangePack); - - this.rpcClient.removeDocument( - req, - { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, - async (err, res) => { - if (err) { - logger.error( - `[RD] c:"${this.getKey()}" d:"${doc.getKey()}" err :`, - err, - ); - reject(err); - return; - } - - const pack = converter.fromChangePack

(res.getChangePack()!); - doc.applyChangePack(pack); - this.detachInternal(doc.getKey()); - logger.info(`[RD] c:"${this.getKey()}" removes d:"${doc.getKey()}"`); - resolve(); + const pbChangePack = converter.toChangePack(doc.createChangePack()); + pbChangePack.isRemoved = true; + return this.rpcClient + .removeDocument( + { + clientId: this.id!, + documentId: attachment.docID, + changePack: pbChangePack, }, - ); - }); + { + headers: { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, + }, + ) + .then((res) => { + const pack = converter.fromChangePack

(res.changePack!); + doc.applyChangePack(pack); + this.detachInternal(doc.getKey()); + + logger.info(`[RD] c:"${this.getKey()}" removes d:"${doc.getKey()}"`); + }) + .catch((err) => { + logger.error(`[RD] c:"${this.getKey()}" err :`, err); + throw err; + }); } /** @@ -823,20 +791,24 @@ export class Client implements Observable { } return attachment.runWatchLoop( - (onDisconnect: () => void): Promise => { + (onDisconnect: () => void): Promise<[WatchStream, AbortController]> => { if (!this.isActive()) { - throw new YorkieError( - Code.ClientNotActive, - `${this.key} is not active`, + return Promise.reject( + new YorkieError(Code.ClientNotActive, `${this.key} is not active`), ); } - const req = new WatchDocumentRequest(); - req.setClientId(this.id!); - req.setDocumentId(attachment.docID); - const stream = this.rpcClient.watchDocument(req, { - 'x-shard-key': `${this.apiKey}/${docKey}`, - }); + const ac = new AbortController(); + const stream = this.rpcClient.watchDocument( + { + clientId: this.id!, + documentId: attachment.docID, + }, + { + headers: { 'x-shard-key': `${this.apiKey}/${docKey}` }, + signal: ac.signal, + }, + ); this.eventStreamObserver.next({ type: ClientEventType.StreamConnectionStatusChanged, @@ -844,22 +816,31 @@ export class Client implements Observable { }); logger.info(`[WD] c:"${this.getKey()}" watches d:"${docKey}"`); - return new Promise((resolve) => { - const onStreamDisconnect = (): void => { - this.eventStreamObserver.next({ - type: ClientEventType.StreamConnectionStatusChanged, - value: StreamConnectionStatus.Disconnected, - }); - logger.debug(`[WD] c:"${this.getKey()}" unwatches`); - onDisconnect(); + return new Promise((resolve, reject) => { + const handleStream = async () => { + try { + for await (const resp of stream) { + this.handleWatchDocumentsResponse(attachment, resp); + + // NOTE(hackerwins): When the first response is received, we need to + // resolve the promise to notify that the watch stream is ready. + if (resp.body.case === 'initialization') { + resolve([stream, ac]); + } + } + } catch (err) { + this.eventStreamObserver.next({ + type: ClientEventType.StreamConnectionStatusChanged, + value: StreamConnectionStatus.Disconnected, + }); + logger.debug(`[WD] c:"${this.getKey()}" unwatches`); + onDisconnect(); + + reject(err); + } }; - stream.on('data', (resp: WatchDocumentResponse) => { - this.handleWatchDocumentsResponse(attachment, resp); - resolve(stream); - }); - stream.on('end', onStreamDisconnect); - stream.on('error', onStreamDisconnect); + handleStream(); }); }, ); @@ -870,8 +851,8 @@ export class Client implements Observable { resp: WatchDocumentResponse, ) { const docKey = attachment.doc.getKey(); - if (resp.hasInitialization()) { - const clientIDs = resp.getInitialization()!.getClientIdsList(); + if (resp.body.case === 'initialization') { + const clientIDs = resp.body.value.clientIds; const onlineClients: Set = new Set(); for (const clientID of clientIDs) { onlineClients.add(clientID); @@ -882,45 +863,45 @@ export class Client implements Observable { value: attachment.doc.getPresences(), }); return; - } - - const pbWatchEvent = resp.getEvent()!; - const eventType = pbWatchEvent.getType(); - const publisher = pbWatchEvent.getPublisher(); - switch (eventType) { - case PbDocEventType.DOC_EVENT_TYPE_DOCUMENT_CHANGED: - attachment.remoteChangeEventReceived = true; - this.eventStreamObserver.next({ - type: ClientEventType.DocumentChanged, - value: [docKey], - }); - break; - case PbDocEventType.DOC_EVENT_TYPE_DOCUMENT_WATCHED: - attachment.doc.addOnlineClient(publisher); - // NOTE(chacha912): We added to onlineClients, but we won't trigger watched event - // unless we also know their initial presence data at this point. - if (attachment.doc.hasPresence(publisher)) { - attachment.doc.publish({ - type: DocEventType.Watched, - value: { - clientID: publisher, - presence: attachment.doc.getPresence(publisher)!, - }, - }); - } - break; - case PbDocEventType.DOC_EVENT_TYPE_DOCUMENT_UNWATCHED: { - const presence = attachment.doc.getPresence(publisher); - attachment.doc.removeOnlineClient(publisher); - // NOTE(chacha912): There is no presence, when PresenceChange(clear) is applied before unwatching. - // In that case, the 'unwatched' event is triggered while handling the PresenceChange. - if (presence) { - attachment.doc.publish({ - type: DocEventType.Unwatched, - value: { clientID: publisher, presence }, + } else if (resp.body.case === 'event') { + const pbWatchEvent = resp.body.value; + const eventType = pbWatchEvent.type; + const publisher = pbWatchEvent.publisher; + switch (eventType) { + case PbDocEventType.DOCUMENT_CHANGED: + attachment.remoteChangeEventReceived = true; + this.eventStreamObserver.next({ + type: ClientEventType.DocumentChanged, + value: [docKey], }); + break; + case PbDocEventType.DOCUMENT_WATCHED: + attachment.doc.addOnlineClient(publisher); + // NOTE(chacha912): We added to onlineClients, but we won't trigger watched event + // unless we also know their initial presence data at this point. + if (attachment.doc.hasPresence(publisher)) { + attachment.doc.publish({ + type: DocEventType.Watched, + value: { + clientID: publisher, + presence: attachment.doc.getPresence(publisher)!, + }, + }); + } + break; + case PbDocEventType.DOCUMENT_UNWATCHED: { + const presence = attachment.doc.getPresence(publisher); + attachment.doc.removeOnlineClient(publisher); + // NOTE(chacha912): There is no presence, when PresenceChange(clear) is applied before unwatching. + // In that case, the 'unwatched' event is triggered while handling the PresenceChange. + if (presence) { + attachment.doc.publish({ + type: DocEventType.Unwatched, + value: { clientID: publisher, presence }, + }); + } + break; } - break; } } } @@ -951,63 +932,52 @@ export class Client implements Observable { syncMode: SyncMode, ): Promise> { const { doc, docID } = attachment; - return new Promise((resolve, reject) => { - const req = new PushPullChangesRequest(); - req.setClientId(this.id!); - req.setDocumentId(docID); - const reqPack = doc.createChangePack(); - const localSize = reqPack.getChangeSize(); - req.setChangePack(converter.toChangePack(reqPack)); - req.setPushOnly(syncMode === SyncMode.PushOnly); - - let isRejected = false; - this.rpcClient - .pushPullChanges( - req, - { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, - (err, res) => { - if (err) { - logger.error(`[PP] c:"${this.getKey()}" err :`, err); - - isRejected = true; - reject(err); - return; - } - - const respPack = converter.fromChangePack

(res.getChangePack()!); - - // NOTE(chacha912, hackerwins): If syncLoop already executed with - // PushPull, ignore the response when the syncMode is PushOnly. - if (respPack.hasChanges() && syncMode === SyncMode.PushOnly) { - return; - } - doc.applyChangePack(respPack); - this.eventStreamObserver.next({ - type: ClientEventType.DocumentSynced, - value: DocumentSyncResultType.Synced, - }); - // NOTE(chacha912): If a document has been removed, watchStream should - // be disconnected to not receive an event for that document. - if (doc.getStatus() === DocumentStatus.Removed) { - this.detachInternal(doc.getKey()); - } + const reqPack = doc.createChangePack(); + return this.rpcClient + .pushPullChanges( + { + clientId: this.id!, + documentId: docID, + changePack: converter.toChangePack(reqPack), + pushOnly: syncMode === SyncMode.PushOnly, + }, + { + headers: { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` }, + }, + ) + .then((res) => { + const respPack = converter.fromChangePack

(res.changePack!); + + // (chacha912, hackerwins): If syncLoop already executed with + // PushPull, ignore the response when the syncMode is PushOnly. + if (respPack.hasChanges() && syncMode === SyncMode.PushOnly) { + return doc; + } - const docKey = doc.getKey(); - const remoteSize = respPack.getChangeSize(); - logger.info( - `[PP] c:"${this.getKey()}" sync d:"${docKey}", push:${localSize} pull:${remoteSize} cp:${respPack - .getCheckpoint() - .toTestString()}`, - ); - }, - ) - .on('end', () => { - if (isRejected) { - return; - } - resolve(doc); + doc.applyChangePack(respPack); + this.eventStreamObserver.next({ + type: ClientEventType.DocumentSynced, + value: DocumentSyncResultType.Synced, }); - }); + // (chacha912): If a document has been removed, watchStream should + // be disconnected to not receive an event for that document. + if (doc.getStatus() === DocumentStatus.Removed) { + this.detachInternal(doc.getKey()); + } + + const docKey = doc.getKey(); + const remoteSize = respPack.getChangeSize(); + logger.info( + `[PP] c:"${this.getKey()}" sync d:"${docKey}", push:${reqPack.getChangeSize()} pull:${remoteSize} cp:${respPack + .getCheckpoint() + .toTestString()}`, + ); + return doc; + }) + .catch((err) => { + logger.error(`[PP] c:"${this.getKey()}" err :`, err); + throw err; + }); } } diff --git a/src/client/metric_interceptor.ts b/src/client/metric_interceptor.ts index 80414dd54..969e53809 100644 --- a/src/client/metric_interceptor.ts +++ b/src/client/metric_interceptor.ts @@ -15,35 +15,15 @@ */ import pkg from '../../package.json'; +import { Interceptor } from '@connectrpc/connect'; /** - * `MetricUnaryInterceptor` is a unary interceptor to add the yorkie user agent header - * for each request. + * `createMetricInterceptor` creates an interceptor to add the x-yorkie-user-agent header for each + * request. */ -export class MetricUnaryInterceptor { - /** - * `intercept` intercepts the request and adds the token to the metadata. - */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - public intercept(request: any, invoker: any): any { - const metadata = request.getMetadata(); - metadata['x-yorkie-user-agent'] = pkg.name + '/' + pkg.version; - return invoker(request); - } -} - -/** - * `MetricStreamInterceptor` is a stream interceptor to add the yorkie user agent header - * for each request. - */ -export class MetricStreamInterceptor { - /** - * `intercept` intercepts the request and adds the token to the metadata. - */ - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - public intercept(request: any, invoker: any): any { - const metadata = request.getMetadata(); - metadata['x-yorkie-user-agent'] = pkg.name + '/' + pkg.version; - return invoker(request); - } +export function createMetricInterceptor(): Interceptor { + return (next) => async (req) => { + req.header.set('x-yorkie-user-agent', pkg.name + '/' + pkg.version); + return await next(req); + }; } diff --git a/test/integration/client_test.ts b/test/integration/client_test.ts index 6e2b4eb37..78e2cc802 100644 --- a/test/integration/client_test.ts +++ b/test/integration/client_test.ts @@ -89,31 +89,22 @@ describe.sequential('Client', function () { await c1.sync(); assert.equal(d1.toSortedJSON(), d2.toSortedJSON()); - vi.stubGlobal( - 'XMLHttpRequest', - vi.fn(() => ({ - send: (req: any) => { - req.respond( - 400, - { 'Content-Type': 'application/grpc-web-text+proto' }, - '', - ); - }, - abort: vi.fn(() => { - throw new Error('INVALID_STATE_ERR - 0'); - }), - })), - ); + // Simulate network error with fetch + vi.stubGlobal('fetch', () => { + return Promise.resolve().then(() => { + throw new Error('Failed to fetch'); + }); + }); d2.update((root) => { root['k1'] = 'v1'; }); await c2.sync().catch((err) => { - assert.equal(err.message, 'INVALID_STATE_ERR - 0'); + assert.equal(err.message, '[unknown] Failed to fetch'); }); await c1.sync().catch((err) => { - assert.equal(err.message, 'INVALID_STATE_ERR - 0'); + assert.equal(err.message, '[unknown] Failed to fetch'); }); assert.equal(d1.toSortedJSON(), '{"k1":"undefined"}'); assert.equal(d2.toSortedJSON(), '{"k1":"v1"}'); @@ -186,21 +177,11 @@ describe.sequential('Client', function () { eventCollectorC2.reset(); // Simulate network error - vi.stubGlobal( - 'XMLHttpRequest', - vi.fn(() => ({ - send: (req: any) => { - req.respond( - 400, - { 'Content-Type': 'application/grpc-web-text+proto' }, - '', - ); - }, - abort: vi.fn(() => { - throw new Error('INVALID_STATE_ERR - 0'); - }), - })), - ); + vi.stubGlobal('fetch', () => { + return Promise.resolve().then(() => { + throw new Error('Failed to fetch'); + }); + }); d2.update((root) => { root['k1'] = 'v1'; @@ -210,7 +191,7 @@ describe.sequential('Client', function () { await eventCollectorC2.waitFor(DocumentSyncResultType.SyncFailed); // c2 should fail to sync await c1.sync().catch((err) => { - assert.equal(err.message, 'INVALID_STATE_ERR - 0'); // c1 should also fail to sync + assert.equal(err.message, '[unknown] Failed to fetch'); // c1 should also fail to sync }); await eventCollectorC1.waitFor(DocumentSyncResultType.SyncFailed); assert.equal(d1.toSortedJSON(), '{"k1":"undefined"}'); diff --git a/test/integration/integration_helper.ts b/test/integration/integration_helper.ts index 63e6cc856..ceda8c8d4 100644 --- a/test/integration/integration_helper.ts +++ b/test/integration/integration_helper.ts @@ -4,7 +4,7 @@ import { Client } from '@yorkie-js-sdk/src/client/client'; import { Document } from '@yorkie-js-sdk/src/document/document'; import { Indexable } from '@yorkie-js-sdk/test/helper/helper'; -export const testRPCAddr = process.env.TEST_RPC_ADDR || 'http://localhost:8080'; +export const testRPCAddr = process.env.TEST_RPC_ADDR || 'http://127.0.0.1:8080'; export function toDocKey(title: string): string { return title diff --git a/test/integration/presence_test.ts b/test/integration/presence_test.ts index c45f2dc41..cd1949ac2 100644 --- a/test/integration/presence_test.ts +++ b/test/integration/presence_test.ts @@ -114,43 +114,38 @@ describe('Presence', function () { const c2ID = c2.getID()!; const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); - const eventCollectorP1 = new EventCollector(); - const eventCollectorP2 = new EventCollector(); - type PresenceType = { name: string }; - const doc1 = new yorkie.Document<{}, PresenceType>(docKey); + const events1 = new EventCollector(); + const events2 = new EventCollector(); + + const doc1 = new yorkie.Document<{}, { name: string }>(docKey); await c1.attach(doc1, { initialPresence: { name: 'a' } }); - const stub1 = vi.fn().mockImplementation((event) => { - eventCollectorP1.add(event); - }); - const unsub1 = doc1.subscribe('presence', stub1); + const unsub1 = doc1.subscribe('presence', (event) => events1.add(event)); - const doc2 = new yorkie.Document<{}, PresenceType>(docKey); + const doc2 = new yorkie.Document<{}, { name: string }>(docKey); await c2.attach(doc2, { initialPresence: { name: 'b' } }); - const stub2 = vi.fn().mockImplementation((event) => { - eventCollectorP2.add(event); - }); - const unsub2 = doc2.subscribe('presence', stub2); - await eventCollectorP1.waitAndVerifyNthEvent(1, { + const unsub2 = doc2.subscribe('presence', (event) => events2.add(event)); + + await events1.waitAndVerifyNthEvent(1, { type: DocEventType.Watched, value: { clientID: c2ID, presence: { name: 'b' } }, }); - doc1.update((root, p) => p.set({ name: 'A' })); - doc2.update((root, p) => p.set({ name: 'B' })); + doc1.update((r, p) => p.set({ name: 'A' })); + doc2.update((r, p) => p.set({ name: 'B' })); - await eventCollectorP1.waitAndVerifyNthEvent(2, { + await events1.waitAndVerifyNthEvent(2, { type: DocEventType.PresenceChanged, value: { clientID: c1ID, presence: { name: 'A' } }, }); - await eventCollectorP1.waitAndVerifyNthEvent(3, { + await events1.waitAndVerifyNthEvent(3, { type: DocEventType.PresenceChanged, value: { clientID: c2ID, presence: { name: 'B' } }, }); - await eventCollectorP2.waitAndVerifyNthEvent(1, { + await events2.waitAndVerifyNthEvent(1, { type: DocEventType.PresenceChanged, value: { clientID: c2ID, presence: { name: 'B' } }, }); - await eventCollectorP2.waitAndVerifyNthEvent(2, { + await events2.waitAndVerifyNthEvent(2, { type: DocEventType.PresenceChanged, value: { clientID: c1ID, presence: { name: 'A' } }, }); @@ -423,6 +418,9 @@ describe(`Document.Subscribe('presence')`, function () { it(`Can receive presence-related event only when using realtime sync`, async function ({ task, }) { + type PresenceType = { name: string; cursor: { x: number; y: number } }; + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const c1 = new yorkie.Client(testRPCAddr); const c2 = new yorkie.Client(testRPCAddr); const c3 = new yorkie.Client(testRPCAddr); @@ -432,17 +430,12 @@ describe(`Document.Subscribe('presence')`, function () { const c2ID = c2.getID()!; const c3ID = c3.getID()!; - const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); - type PresenceType = { name: string; cursor: { x: number; y: number } }; const doc1 = new yorkie.Document<{}, PresenceType>(docKey); await c1.attach(doc1, { initialPresence: { name: 'a1', cursor: { x: 0, y: 0 } }, }); - const eventCollector = new EventCollector(); - const stub = vi.fn().mockImplementation((event) => { - eventCollector.add(event); - }); - const unsub = doc1.subscribe('presence', stub); + const events = new EventCollector(); + const unsub = doc1.subscribe('presence', (event) => events.add(event)); // 01. c2 attaches doc in realtime sync, and c3 attached doc in manual sync. // c1 receives the watched event from c2. @@ -455,7 +448,7 @@ describe(`Document.Subscribe('presence')`, function () { initialPresence: { name: 'c1', cursor: { x: 0, y: 0 } }, isRealtimeSync: false, }); - await eventCollector.waitAndVerifyNthEvent(1, { + await events.waitAndVerifyNthEvent(1, { type: DocEventType.Watched, value: { clientID: c2ID, @@ -465,13 +458,9 @@ describe(`Document.Subscribe('presence')`, function () { // 02. c2 and c3 update the presence. // c1 receives the presence-changed event from c2. - doc2.update((_, presence) => { - presence.set({ name: 'b2' }); - }); - doc3.update((_, presence) => { - presence.set({ name: 'c2' }); - }); - await eventCollector.waitAndVerifyNthEvent(2, { + doc2.update((_, p) => p.set({ name: 'b2' })); + doc3.update((_, p) => p.set({ name: 'c2' })); + await events.waitAndVerifyNthEvent(2, { type: DocEventType.PresenceChanged, value: { clientID: c2ID, @@ -481,7 +470,7 @@ describe(`Document.Subscribe('presence')`, function () { // 03-1. c2 pauses the document, c1 receives an unwatched event from c2. await c2.pause(doc2); - await eventCollector.waitAndVerifyNthEvent(3, { + await events.waitAndVerifyNthEvent(3, { type: DocEventType.Unwatched, value: { clientID: c2ID, @@ -496,7 +485,7 @@ describe(`Document.Subscribe('presence')`, function () { await c3.sync(); await c1.sync(); await c3.resume(doc3); - await eventCollector.waitAndVerifyNthEvent(4, { + await events.waitAndVerifyNthEvent(4, { type: DocEventType.Watched, value: { clientID: c3ID, @@ -506,13 +495,9 @@ describe(`Document.Subscribe('presence')`, function () { // 04. c2 and c3 update the presence. // c1 receives the presence-changed event from c3. - doc2.update((_, presence) => { - presence.set({ name: 'b3' }); - }); - doc3.update((_, presence) => { - presence.set({ name: 'c3' }); - }); - await eventCollector.waitAndVerifyNthEvent(5, { + doc2.update((_, p) => p.set({ name: 'b3' })); + doc3.update((_, p) => p.set({ name: 'c3' })); + await events.waitAndVerifyNthEvent(5, { type: DocEventType.PresenceChanged, value: { clientID: c3ID, @@ -522,7 +507,7 @@ describe(`Document.Subscribe('presence')`, function () { // 05-1. c3 pauses the document, c1 receives an unwatched event from c3. await c3.pause(doc3); - await eventCollector.waitAndVerifyNthEvent(6, { + await events.waitAndVerifyNthEvent(6, { type: DocEventType.Unwatched, value: { clientID: c3ID, @@ -534,7 +519,7 @@ describe(`Document.Subscribe('presence')`, function () { await c2.sync(); await c1.sync(); await c2.resume(doc2); - await eventCollector.waitAndVerifyNthEvent(7, { + await events.waitAndVerifyNthEvent(7, { type: DocEventType.Watched, value: { clientID: c2ID, From 31212051fd01f1913e352476c6c9312dd8b9d7a9 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 18 Dec 2023 11:10:19 +0900 Subject: [PATCH 19/48] Update CHANGELOG.md for v0.4.11 (#711) --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41768f2c8..a341fe0d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +## [0.4.11] - 2023-12-18 + +### Added +* Address duplicate node IDs in Tree.Split by @sejongk, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/707 +* Add test filtering and log printing guide to CONTRIBUTING.md by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/708 +* Support concurrent insertion and splitting in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/709 + +### Changed +* Migrate RPC to ConnectRPC by @krapie, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/698 + ## [0.4.10] - 2023-12-04 ### Added diff --git a/package.json b/package.json index c468833ee..5071349da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.10", + "version": "0.4.11", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index aee2a3a64..7ec424e0c 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.10", + "version": "0.4.11", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 5ef1e8ff13cde39053d86fa667dc7afb857aa72b Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 18 Dec 2023 11:40:39 +0900 Subject: [PATCH 20/48] Remove invalid internals in Document Related to https://github.com/yorkie-team/codepair/pull/288 --- src/document/document.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/document/document.ts b/src/document/document.ts index 0dbc4d441..9ad0e1dac 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -858,8 +858,6 @@ export class Document { /** * `hasLocalChanges` returns whether this document has local changes or not. - * - * @internal */ public hasLocalChanges(): boolean { return this.localChanges.length > 0; @@ -910,8 +908,6 @@ export class Document { /** * `getKey` returns the key of this document. - * - * @internal */ public getKey(): string { return this.key; @@ -928,8 +924,6 @@ export class Document { /** * `getStatus` returns the status of this document. - * - * @internal */ public getStatus(): DocumentStatus { return this.status; From a714e662ebfcfd6c2080ac8c67ea0ebd7d306699 Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Thu, 4 Jan 2024 11:53:43 +0900 Subject: [PATCH 21/48] Add concurrent editing test cases in Tree (#710) This PR enhances test coverage for concurrent editing in Tree CRDT. The 8 skipped tests correspond to the TODOs within the Tree implementation. --- test/integration/tree_test.ts | 1332 ++++++++++++++++++++++++++------- 1 file changed, 1056 insertions(+), 276 deletions(-) diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index aa702a4c4..8a798ae3c 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -1252,6 +1252,71 @@ describe('Concurrent editing, overlapping range', () => { assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); }, task.name); }); + + it('overlapping-merge-and-merge', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(5, 7)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

c

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

bc

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

abc

`); + }, task.name); + }); + + it.skip('overlapping-merge-and-delete', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); + + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(3, 6)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

`); + }, task.name); + }); }); describe('Concurrent editing, contained range', () => { @@ -1543,88 +1608,76 @@ describe('Concurrent editing, contained range', () => { assert.equal(d2.getRoot().t.toXML(), /*html*/ ``); }, task.name); }); -}); -describe('Concurrent editing, side by side range', () => { - it('Can concurrently insert side by side elements (left)', async function ({ + it('contained-split-and-split-at-the-same-position', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [ - { - type: 'p', - children: [], - }, - ], + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); - d1.update((r) => r.t.edit(0, 0, { type: 'b', children: [] })); - d2.update((r) => r.t.edit(0, 0, { type: 'i', children: [] })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(2, 2, undefined, 1)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); await c1.sync(); await c2.sync(); await c1.sync(); assert.equal( d1.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

`, ); assert.equal( d2.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

`, ); }, task.name); }); - it('Can concurrently insert side by side elements (middle)', async function ({ + it('contained-split-and-split-at-diffrent-positions-on-the-same-node', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [ - { - type: 'p', - children: [], - }, - ], + children: [{ type: 'p', children: [{ type: 'text', value: 'abc' }] }], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

abc

`); - d1.update((r) => r.t.edit(1, 1, { type: 'b', children: [] })); - d2.update((r) => r.t.edit(1, 1, { type: 'i', children: [] })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(3, 3, undefined, 1)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

bc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

c

`); await c1.sync(); await c2.sync(); await c1.sync(); assert.equal( d1.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

c

`, ); assert.equal( d2.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

c

`, ); }, task.name); }); - it('Can concurrently insert side by side elements (right)', async function ({ + it.skip('contained-split-and-split-at-different-levels', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { @@ -1634,110 +1687,189 @@ describe('Concurrent editing, side by side range', () => { children: [ { type: 'p', - children: [], + children: [ + { type: 'p', children: [{ type: 'text', value: 'ab' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, + ], }, ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

c

`, + ); - d1.update((r) => r.t.edit(2, 2, { type: 'b', children: [] })); - d2.update((r) => r.t.edit(2, 2, { type: 'i', children: [] })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + d1.update((r) => r.t.edit(3, 3, undefined, 1)); + d2.update((r) => r.t.edit(5, 5, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

c

`, + ); await c1.sync(); await c2.sync(); await c1.sync(); assert.equal( d1.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

c

`, ); assert.equal( d2.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

c

`, ); }, task.name); }); - it('Can concurrently insert and delete side by side elements', async function ({ + it('contained-split-and-insert-into-the-split-position', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [ - { - type: 'p', - children: [{ type: 'b', children: [] }], - }, - ], + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); - d1.update((r) => r.t.edit(1, 3)); - d2.update((r) => r.t.edit(1, 1, { type: 'i', children: [] })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal( - d2.getRoot().t.toXML(), - /*html*/ `

`, - ); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(2, 2, { type: 'text', value: 'c' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

acb

`); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ac

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ac

b

`); }, task.name); }); - it('Can concurrently delete and insert side by side elements', async function ({ + it('contained-split-and-insert-into-original-node', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [ - { - type: 'p', - children: [{ type: 'b', children: [] }], - }, - ], + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); - d1.update((r) => r.t.edit(1, 3)); - d2.update((r) => r.t.edit(3, 3, { type: 'i', children: [] })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal( - d2.getRoot().t.toXML(), - /*html*/ `

`, - ); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(1, 1, { type: 'text', value: 'c' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

cab

`); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ca

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ca

b

`); }, task.name); }); - it('Can concurrently delete side by side elements', async function ({ + it('contained-split-and-insert-into-split-node', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); + + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(3, 3, { type: 'text', value: 'c' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

abc

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

bc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

bc

`); + }, task.name); + }); + + it('contained-split-and-delete-contents-in-split-node', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); + + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(2, 3)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

`); + }, task.name); + }); + + it.skip('contained-split-and-delete-the-whole-original-and-split-nodes', async function ({ task, }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); + + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(0, 4)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ ``); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); + assert.equal(d2.getRoot().t.toXML(), /*html*/ ``); + }, task.name); + }); + + it('contained-merge-and-merge', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -1746,10 +1878,11 @@ describe('Concurrent editing, side by side range', () => { { type: 'p', children: [ - { type: 'b', children: [] }, - { type: 'i', children: [] }, + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, ], }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, ], }); }); @@ -1757,281 +1890,1008 @@ describe('Concurrent editing, side by side range', () => { await c2.sync(); assert.equal( d1.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

c

`, ); assert.equal( d2.getRoot().t.toXML(), - /*html*/ `

`, + /*html*/ `

a

b

c

`, ); - d1.update((r) => r.t.edit(1, 3)); - d2.update((r) => r.t.edit(3, 5)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + d1.update((r) => r.t.edit(3, 5)); + d2.update((r) => r.t.edit(7, 9)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

c

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

c

`); }, task.name); }); - it('Can insert text to the same position(left) concurrently', async function ({ - task, - }) { + it.skip('contained-merge-and-insert', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [{ type: 'p', children: [{ type: 'text', value: '12' }] }], + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); - d1.update((r) => r.t.edit(1, 1, { type: 'text', value: 'A' })); - d2.update((r) => r.t.edit(1, 1, { type: 'text', value: 'B' })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

A12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

B12

`); + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(4, 4, { type: 'text', value: 'c' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

cb

`); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

BA12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

BA12

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

acb

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

acb

`); + }, task.name); + }); + + it('contained-merge-and-delete-the-whole', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); + + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(0, 6)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ ``); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); + assert.equal(d2.getRoot().t.toXML(), /*html*/ ``); + }, task.name); + }); + + it.skip('contained-merge-and-delete-contents-in-merged-node', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'bc' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

bc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

bc

`); + + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(4, 5)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

c

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ac

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ac

`); + }, task.name); + }); + + it('contained-merge-and-delete-sub-range-in-merged-range', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + + d1.update((r) => r.t.edit(2, 7)); + d2.update((r) => r.t.edit(3, 6)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ac

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

c

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ac

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ac

`); + }, task.name); + }); + + it('contained-merge-and-split-merged-node', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'bc' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

bc

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

bc

`); + + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(5, 5, undefined, 1)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abc

`); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

c

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

c

`); + }, task.name); + }); + + it('contained-merge-and-split-at-multi-levels', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + ], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

`, + ); + + d1.update((r) => r.t.edit(3, 5)); + d2.update((r) => r.t.edit(4, 4, undefined, 1)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

`, + ); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

`, + ); + }, task.name); + }); +}); + +describe('Concurrent editing, side by side range', () => { + it('Can concurrently insert side by side elements (left)', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + d1.update((r) => r.t.edit(0, 0, { type: 'b', children: [] })); + d2.update((r) => r.t.edit(0, 0, { type: 'i', children: [] })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

`, + ); + }, task.name); + }); + + it('Can concurrently insert side by side elements (middle)', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + d1.update((r) => r.t.edit(1, 1, { type: 'b', children: [] })); + d2.update((r) => r.t.edit(1, 1, { type: 'i', children: [] })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

`, + ); + }, task.name); + }); + + it('Can concurrently insert side by side elements (right)', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + d1.update((r) => r.t.edit(2, 2, { type: 'b', children: [] })); + d2.update((r) => r.t.edit(2, 2, { type: 'i', children: [] })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

`, + ); + }, task.name); + }); + + it('Can concurrently insert and delete side by side elements', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [{ type: 'b', children: [] }], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + d1.update((r) => r.t.edit(1, 3)); + d2.update((r) => r.t.edit(1, 1, { type: 'i', children: [] })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

`, + ); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + }, task.name); + }); + + it('Can concurrently delete and insert side by side elements', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [{ type: 'b', children: [] }], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + d1.update((r) => r.t.edit(1, 3)); + d2.update((r) => r.t.edit(3, 3, { type: 'i', children: [] })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

`, + ); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + }, task.name); + }); + + it('Can concurrently delete side by side elements', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { + type: 'p', + children: [ + { type: 'b', children: [] }, + { type: 'i', children: [] }, + ], + }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

`, + ); + + d1.update((r) => r.t.edit(1, 3)); + d2.update((r) => r.t.edit(3, 5)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + }, task.name); + }); + + it('Can insert text to the same position(left) concurrently', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: '12' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + + d1.update((r) => r.t.edit(1, 1, { type: 'text', value: 'A' })); + d2.update((r) => r.t.edit(1, 1, { type: 'text', value: 'B' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

A12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

B12

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

BA12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

BA12

`); + }, task.name); + }); + + it('Can insert text to the same position(middle) concurrently', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: '12' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + + d1.update((r) => r.t.edit(2, 2, { type: 'text', value: 'A' })); + d2.update((r) => r.t.edit(2, 2, { type: 'text', value: 'B' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1A2

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1B2

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1BA2

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1BA2

`); + }, task.name); + }); + + it('Can insert text content to the same position(right) concurrently', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: '12' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + + d1.update((r) => r.t.edit(3, 3, { type: 'text', value: 'A' })); + d2.update((r) => r.t.edit(3, 3, { type: 'text', value: 'B' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12A

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12B

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12BA

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12BA

`); + }, task.name); + }); + + it('Can concurrently insert and delete side by side text', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: '1234' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1234

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1234

`); + + d1.update((r) => r.t.edit(3, 3, { type: 'text', value: 'a' })); + d2.update((r) => r.t.edit(3, 5)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12a34

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12a

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12a

`); + }, task.name); + }); + + it('Can concurrently delete and insert side by side text', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: '1234' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1234

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1234

`); + + d1.update((r) => r.t.edit(3, 3, { type: 'text', value: 'a' })); + d2.update((r) => r.t.edit(1, 3)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12a34

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

34

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a34

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a34

`); + }, task.name); + }); + + it('Can concurrently delete side by side text blocks', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: '1234' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1234

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1234

`); + + d1.update((r) => r.t.edit(3, 5)); + d2.update((r) => r.t.edit(1, 3)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

34

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + }, task.name); + }); + + it('Can delete text content at the same position(left) concurrently', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: '123' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

123

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

123

`); + + d1.update((r) => r.t.edit(1, 2)); + d2.update((r) => r.t.edit(1, 2)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

23

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

23

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

23

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

23

`); + }, task.name); + }); + + it('Can delete text content at the same position(middle) concurrently', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [{ type: 'p', children: [{ type: 'text', value: '123' }] }], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

123

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

123

`); + + d1.update((r) => r.t.edit(2, 3)); + d2.update((r) => r.t.edit(2, 3)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

13

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

13

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

13

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

13

`); }, task.name); }); - it('Can insert text to the same position(middle) concurrently', async function ({ + it('Can delete text content at the same position(right) concurrently', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [{ type: 'p', children: [{ type: 'text', value: '12' }] }], + children: [{ type: 'p', children: [{ type: 'text', value: '123' }] }], }); }); await c1.sync(); await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

123

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

123

`); + + d1.update((r) => r.t.edit(3, 4)); + d2.update((r) => r.t.edit(3, 4)); assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); - d1.update((r) => r.t.edit(2, 2, { type: 'text', value: 'A' })); - d2.update((r) => r.t.edit(2, 2, { type: 'text', value: 'B' })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1A2

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1B2

`); - await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1BA2

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1BA2

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); }, task.name); }); - it('Can insert text content to the same position(right) concurrently', async function ({ - task, - }) { + it('side-by-side-split-and-split', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [{ type: 'p', children: [{ type: 'text', value: '12' }] }], + children: [ + { type: 'p', children: [{ type: 'text', value: 'ab' }] }, + { type: 'p', children: [{ type: 'text', value: 'cd' }] }, + ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); - d1.update((r) => r.t.edit(3, 3, { type: 'text', value: 'A' })); - d2.update((r) => r.t.edit(3, 3, { type: 'text', value: 'B' })); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12A

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12B

`); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(6, 6, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

cd

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

c

d

`, + ); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12BA

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12BA

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

d

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

d

`, + ); }, task.name); }); - it('Can concurrently insert and delete side by side text', async function ({ - task, - }) { + it.skip('side-by-side-split-and-insert', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [ - { type: 'p', children: [{ type: 'text', value: '1234' }] }, - ], + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1234

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1234

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); - d1.update((r) => r.t.edit(3, 3, { type: 'text', value: 'a' })); - d2.update((r) => r.t.edit(3, 5)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12a34

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => + r.t.edit(4, 4, { type: 'p', children: [{ type: 'text', value: 'c' }] }), + ); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

c

`); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12a

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12a

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); }, task.name); }); - it('Can concurrently delete and insert side by side text', async function ({ - task, - }) { + it.skip('side-by-side-split-and-delete', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', children: [ - { type: 'p', children: [{ type: 'text', value: '1234' }] }, + { type: 'p', children: [{ type: 'text', value: 'ab' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1234

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1234

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

c

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

c

`); - d1.update((r) => r.t.edit(3, 3, { type: 'text', value: 'a' })); - d2.update((r) => r.t.edit(1, 3)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12a34

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

34

`); + d1.update((r) => r.t.edit(2, 2, undefined, 1)); + d2.update((r) => r.t.edit(4, 7)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a34

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a34

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); }, task.name); }); - it('Can concurrently delete side by side text blocks', async function ({ - task, - }) { + it('side-by-side-merge-and-merge', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', children: [ - { type: 'p', children: [{ type: 'text', value: '1234' }] }, + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, + { type: 'p', children: [{ type: 'text', value: 'd' }] }, ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

1234

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

1234

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

d

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

d

`, + ); - d1.update((r) => r.t.edit(3, 5)); - d2.update((r) => r.t.edit(1, 3)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

34

`); + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(8, 10)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

c

d

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

cd

`, + ); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); }, task.name); }); - it('Can delete text content at the same position(left) concurrently', async function ({ - task, - }) { + it('side-by-side-merge-and-insert', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [{ type: 'p', children: [{ type: 'text', value: '123' }] }], + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

123

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

123

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

a

b

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); - d1.update((r) => r.t.edit(1, 2)); - d2.update((r) => r.t.edit(1, 2)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

23

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

23

`); + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => + r.t.edit(6, 6, { type: 'p', children: [{ type: 'text', value: 'c' }] }), + ); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

23

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

23

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

c

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

c

`); }, task.name); }); - it('Can delete text content at the same position(middle) concurrently', async function ({ - task, - }) { + it('side-by-side-merge-and-delete', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [{ type: 'p', children: [{ type: 'text', value: '123' }] }], + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, + ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

123

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

123

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); - d1.update((r) => r.t.edit(2, 3)); - d2.update((r) => r.t.edit(2, 3)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

13

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

13

`); + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(6, 9)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

c

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

b

`); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

13

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

13

`); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ab

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ab

`); }, task.name); }); - it('Can delete text content at the same position(right) concurrently', async function ({ - task, - }) { + it('side-by-side-merge-and-split', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ type: 'r', - children: [{ type: 'p', children: [{ type: 'text', value: '123' }] }], + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + { type: 'p', children: [{ type: 'text', value: 'cd' }] }, + ], }); }); await c1.sync(); await c2.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

123

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

123

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

cd

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

cd

`, + ); - d1.update((r) => r.t.edit(3, 4)); - d2.update((r) => r.t.edit(3, 4)); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(8, 8, undefined, 1)); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

cd

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

d

`, + ); await c1.sync(); await c2.sync(); await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

12

`); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

12

`); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

ab

c

d

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

ab

c

d

`, + ); }, task.name); }); }); @@ -2733,84 +3593,4 @@ describe('testing edge cases', () => { assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); }, task.name); }); - - it('Can concurrently split and insert into original node', async function ({ - task, - }) { - await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { - d1.update((root) => { - root.t = new Tree({ - type: 'doc', - children: [ - { - type: 'p', - children: [ - { type: 'text', value: 'a' }, - { type: 'text', value: 'b' }, - { type: 'text', value: 'c' }, - { type: 'text', value: 'd' }, - ], - }, - ], - }); - }); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abcd

`); - await c1.sync(); - await c2.sync(); - - d1.update((root) => root.t.edit(3, 3, undefined, 1)); - assert.equal( - d1.getRoot().t.toXML(), - /*html*/ `

ab

cd

`, - ); - - d2.update((root) => root.t.edit(2, 2, { type: 'text', value: 'e' })); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

aebcd

`); - - await c1.sync(); - await c2.sync(); - await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); - }, task.name); - }); - - it('Can concurrently split and insert into split node', async function ({ - task, - }) { - await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { - d1.update((root) => { - root.t = new Tree({ - type: 'doc', - children: [ - { - type: 'p', - children: [ - { type: 'text', value: 'a' }, - { type: 'text', value: 'b' }, - { type: 'text', value: 'c' }, - { type: 'text', value: 'd' }, - ], - }, - ], - }); - }); - assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abcd

`); - await c1.sync(); - await c2.sync(); - - d1.update((root) => root.t.edit(3, 3, undefined, 1)); - assert.equal( - d1.getRoot().t.toXML(), - /*html*/ `

ab

cd

`, - ); - - d2.update((root) => root.t.edit(4, 4, { type: 'text', value: 'e' })); - assert.equal(d2.getRoot().t.toXML(), /*html*/ `

abced

`); - - await c1.sync(); - await c2.sync(); - await c1.sync(); - assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); - }, task.name); - }); }); From 48c3ccbab9d24162c232ddf809ed371a02eacff0 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:01:42 +0900 Subject: [PATCH 22/48] Add forced sync when switching to realtime mode (#713) In manual mode, the client does not receive change events from the server. Therefore, we need to set `remoteChangeEventReceived` to true to sync the local and remote changes. This has limitations in that unnecessary syncs occur if the client and server do not have any changes. --------- Co-authored-by: Youngteac Hong --- src/client/client.ts | 5 +++ test/integration/client_test.ts | 73 +++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/client/client.ts b/src/client/client.ts index 87e784cc0..b29b64d20 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -615,6 +615,11 @@ export class Client implements Observable { } if (isRealtimeSync) { + // NOTE(hackerwins): In manual mode, the client does not receive change events + // from the server. Therefore, we need to set `remoteChangeEventReceived` to true + // to sync the local and remote changes. This has limitations in that unnecessary + // syncs occur if the client and server do not have any changes. + attachment.remoteChangeEventReceived = true; await this.runWatchLoop(doc.getKey()); return doc; } diff --git a/test/integration/client_test.ts b/test/integration/client_test.ts index 78e2cc802..2f754bfbb 100644 --- a/test/integration/client_test.ts +++ b/test/integration/client_test.ts @@ -219,7 +219,7 @@ describe.sequential('Client', function () { await c2.deactivate(); }); - it('Can change realtime sync', async function ({ task }) { + it('Can change realtime sync (pause/resume)', async function ({ task }) { const c1 = new yorkie.Client(testRPCAddr); const c2 = new yorkie.Client(testRPCAddr); await c1.activate(); @@ -249,6 +249,7 @@ describe.sequential('Client', function () { }); const unsub1 = c2.subscribe(stub); await c2.resume(d2); + await eventCollector.waitFor(ClientEventType.DocumentSynced); // sync occurs when resuming eventCollector.reset(); d1.update((root) => { @@ -276,7 +277,71 @@ describe.sequential('Client', function () { await c2.deactivate(); }); - it('Can change sync mode in manual sync', async function ({ task }) { + it('Should apply previous changes when resuming document', async function ({ + task, + }) { + const c1 = new yorkie.Client(testRPCAddr); + const c2 = new yorkie.Client(testRPCAddr); + await c1.activate(); + await c2.activate(); + + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const d1 = new yorkie.Document<{ version: string }>(docKey); + const d2 = new yorkie.Document<{ version: string }>(docKey); + + const eventCollector = new EventCollector(); + const stub = vi.fn().mockImplementation((event) => { + eventCollector.add(event.type); + }); + const unsub1 = c2.subscribe(stub); + + // 01. c2 attach the doc with realtime sync mode at first. + await c1.attach(d1, { isRealtimeSync: false }); + await c2.attach(d2); + d1.update((root) => { + root.version = 'v1'; + }); + await c1.sync(); + assert.equal(d1.toSortedJSON(), `{"version":"v1"}`, 'd1'); + await eventCollector.waitFor(ClientEventType.DocumentSynced); + assert.equal(d2.toSortedJSON(), `{"version":"v1"}`, 'd2'); + + // 02. c2 pauses realtime sync mode. So, c2 doesn't get the changes of c1. + await c2.pause(d2); + d1.update((root) => { + root.version = 'v2'; + }); + await c1.sync(); + assert.equal(d1.toSortedJSON(), `{"version":"v2"}`, 'd1'); + assert.equal(d2.toSortedJSON(), `{"version":"v1"}`, 'd2'); + + // 03. c2 resumes realtime sync mode. + // c2 should be able to apply changes made to the document while c2 is not in realtime sync. + eventCollector.reset(); + await c2.resume(d2); + + await eventCollector.waitFor(ClientEventType.DocumentSynced); + assert.equal(d2.toSortedJSON(), `{"version":"v2"}`, 'd2'); + + // 04. c2 should automatically synchronize changes. + eventCollector.reset(); + d1.update((root) => { + root.version = 'v3'; + }); + await c1.sync(); + + await eventCollector.waitFor(ClientEventType.DocumentSynced); + assert.equal(d1.toSortedJSON(), `{"version":"v3"}`, 'd1'); + assert.equal(d2.toSortedJSON(), `{"version":"v3"}`, 'd2'); + unsub1(); + + await c1.deactivate(); + await c2.deactivate(); + }); + + it('Can change sync mode in manual sync (SyncMode.PushOnly)', async function ({ + task, + }) { const c1 = new yorkie.Client(testRPCAddr); const c2 = new yorkie.Client(testRPCAddr); const c3 = new yorkie.Client(testRPCAddr); @@ -335,7 +400,9 @@ describe.sequential('Client', function () { await c3.deactivate(); }); - it('Can change sync mode in realtime sync', async function ({ task }) { + it('Can change sync mode in realtime sync (pauseRemoteChanges/resumeRemoteChanges)', async function ({ + task, + }) { const c1 = new yorkie.Client(testRPCAddr); const c2 = new yorkie.Client(testRPCAddr); const c3 = new yorkie.Client(testRPCAddr); From 1c65dd9534ee9545629e0b7f0730a6312ca71f32 Mon Sep 17 00:00:00 2001 From: LeeJongBeom <52884648+devleejb@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:32:52 +0900 Subject: [PATCH 23/48] Fix `getGarbageLen` to retrun correct size (#714) To ensure that the getGarbageLen function returns the correct length, this commit uses a set to eliminate duplicate counting. --- src/document/crdt/root.ts | 9 +++++--- test/integration/gc_test.ts | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/document/crdt/root.ts b/src/document/crdt/root.ts index beecb02f3..9b6e760a4 100644 --- a/src/document/crdt/root.ts +++ b/src/document/crdt/root.ts @@ -233,18 +233,21 @@ export class CRDTRoot { */ public getGarbageLen(): number { let count = 0; + const seen = new Set(); for (const createdAt of this.removedElementSetByCreatedAt) { - count++; + seen.add(createdAt); const pair = this.elementPairMapByCreatedAt.get(createdAt)!; if (pair.element instanceof CRDTContainer) { - pair.element.getDescendants(() => { - count++; + pair.element.getDescendants((el) => { + seen.add(el.getCreatedAt().toIDString()); return false; }); } } + count += seen.size; + for (const createdAt of this.elementHasRemovedNodesSetByCreatedAt) { const pair = this.elementPairMapByCreatedAt.get(createdAt)!; const elem = pair.element as CRDTGCElement; diff --git a/test/integration/gc_test.ts b/test/integration/gc_test.ts index 48b17052a..7f552dede 100644 --- a/test/integration/gc_test.ts +++ b/test/integration/gc_test.ts @@ -114,6 +114,52 @@ describe('Garbage Collection', function () { assert.equal(root, clone); }); + it('getGarbageLen should return the actual number of elements garbage-collected', async function ({ task }) { + type TestDoc = { point?: { x?: number; y?: number } }; + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc1 = new yorkie.Document(docKey); + const doc2 = new yorkie.Document(docKey); + + const client1 = new yorkie.Client(testRPCAddr); + const client2 = new yorkie.Client(testRPCAddr); + + await client1.activate(); + await client2.activate(); + + // 1. initial state + await client1.attach(doc1, { isRealtimeSync: false }); + doc1.update((root) => (root.point = { x: 0, y: 0 })); + await client1.sync(); + await client2.attach(doc2, { isRealtimeSync: false }); + + // 2. client1 updates doc + doc1.update((root) => { + delete root.point; + }); + assert.equal(doc1.getGarbageLen(), 3); // point, x, y + + // 3. client2 updates doc + doc2.update((root) => { + delete root.point?.x; + }); + assert.equal(doc2.getGarbageLen(), 1); // x + + await client1.sync(); + await client2.sync(); + await client1.sync(); + + const gcNodeLen = 3; // point, x, y + assert.equal(doc1.getGarbageLen(), gcNodeLen); + assert.equal(doc2.getGarbageLen(), gcNodeLen); + + // Actual garbage-collected nodes + assert.equal(doc1.garbageCollect(MaxTimeTicket), gcNodeLen); + assert.equal(doc2.garbageCollect(MaxTimeTicket), gcNodeLen); + + await client1.deactivate(); + await client2.deactivate(); + }); + it('text garbage collection test', function () { const doc = new yorkie.Document<{ text: Text }>('test-doc'); doc.update((root) => (root.text = new Text())); From 0b3c584166e8b7edc68167fe4a364563eea3904c Mon Sep 17 00:00:00 2001 From: Jeounghui Nah Date: Thu, 4 Jan 2024 17:04:28 +0900 Subject: [PATCH 24/48] Prevent deregisterElement from deregistering twice in nested object (#716) Prevent deregisterElement from deregistering twice in nested object. Improve time complexity of `deregisterElement` function `O(2^n)` to `O(n)` when n is the number of elements to be deregistered. --- src/document/crdt/root.ts | 13 ++++++------- test/integration/gc_test.ts | 13 +++++++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/document/crdt/root.ts b/src/document/crdt/root.ts index 9b6e760a4..08a0fc359 100644 --- a/src/document/crdt/root.ts +++ b/src/document/crdt/root.ts @@ -176,16 +176,15 @@ export class CRDTRoot { this.elementPairMapByCreatedAt.delete(createdAt); this.removedElementSetByCreatedAt.delete(createdAt); count++; - - if (elem instanceof CRDTContainer) { - elem.getDescendants((e) => { - deregisterElementInternal(e); - return false; - }); - } }; deregisterElementInternal(element); + if (element instanceof CRDTContainer) { + element.getDescendants((e) => { + deregisterElementInternal(e); + return false; + }); + } return count; } diff --git a/test/integration/gc_test.ts b/test/integration/gc_test.ts index 7f552dede..ec2ded131 100644 --- a/test/integration/gc_test.ts +++ b/test/integration/gc_test.ts @@ -728,4 +728,17 @@ describe('Garbage Collection', function () { await client1.deactivate(); await client2.deactivate(); }); + + it('garbage collection test for nested object', async function ({ task }) { + type TestDoc = { shape?: { point?: { x?: number; y?: number } } }; + const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); + const doc = new yorkie.Document(docKey); + + doc.update((root) => { + root.shape = { point: { x: 0, y: 0 } }; + delete root.shape; + }); + assert.equal(doc.getGarbageLen(), 4); // shape, point, x, y + assert.equal(doc.garbageCollect(MaxTimeTicket), 4); // The number of GC nodes must also be 4. + }); }); From 207b65e099651e9ce91dcb58a58a2c446864b0dc Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Fri, 5 Jan 2024 09:52:13 +0900 Subject: [PATCH 25/48] Generate correct TreeChange in concurrent edits (#712) This PR improves concurrent edits by implementing logic for correct TreeChange generation. Changes: - Introduces logic for correct TreeChange generation. - Implements token traversal method. - Ensures accurate inclusion of tokens (Start/End/Text) in ranges. --------- Co-authored-by: Youngteac Hong --- src/document/crdt/tree.ts | 253 ++++++++++++++++++---- src/util/index_tree.ts | 78 ++++--- test/integration/tree_test.ts | 341 ++++++++++++++++++++++++++++++ test/unit/util/index_tree_test.ts | 72 +++---- 4 files changed, 629 insertions(+), 115 deletions(-) diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index f32e8cb72..8934defa6 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -26,7 +26,7 @@ import { TreePos, IndexTreeNode, traverseAll, - TagContained, + TokenType, } from '@yorkie-js-sdk/src/util/index_tree'; import { RHT } from './rht'; import { ActorID } from './../time/actor_id'; @@ -36,6 +36,7 @@ import { parseObjectValues } from '@yorkie-js-sdk/src/util/object'; import type { DefaultTextType, TreeNodeType, + TreeToken, } from '@yorkie-js-sdk/src/util/index_tree'; import { Indexable } from '@yorkie-js-sdk/src/document/document'; import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; @@ -489,7 +490,11 @@ export class CRDTTreeNode extends IndexTreeNode { } if (alived) { - this.updateAncestorsSize(); + if (!this.parent!.removedAt) { + this.updateAncestorsSize(); + } else { + this.parent!.size -= this.paddedSize; + } } } @@ -707,7 +712,7 @@ export class CRDTTree extends CRDTGCElement { const allChildren = realParent.allChildren; const index = isLeftMost ? 0 : allChildren.indexOf(leftNode) + 1; - for (let i = index; i < parent.allChildren.length; i++) { + for (let i = index; i < allChildren.length; i++) { const next = allChildren[i]; if (!next.id.getCreatedAt().after(editedAt)) { break; @@ -743,17 +748,23 @@ export class CRDTTree extends CRDTGCElement { value: attributes ? parseObjectValues(attributes) : undefined, }); - this.traverseInPosRange(fromParent, fromLeft, toParent, toLeft, (node) => { - if (!node.isRemoved && !node.isText && attributes) { - if (!node.attrs) { - node.attrs = new RHT(); - } + this.traverseInPosRange( + fromParent, + fromLeft, + toParent, + toLeft, + ([node]) => { + if (!node.isRemoved && !node.isText && attributes) { + if (!node.attrs) { + node.attrs = new RHT(); + } - for (const [key, value] of Object.entries(attributes)) { - node.attrs.set(key, value, editedAt); + for (const [key, value] of Object.entries(attributes)) { + node.attrs.set(key, value, editedAt); + } } - } - }); + }, + ); return changes; } @@ -777,7 +788,11 @@ export class CRDTTree extends CRDTGCElement { ); const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); - const toBeRemoveds: Array = []; + const fromIdx = this.toIndex(fromParent, fromLeft); + const fromPath = this.toPath(fromParent, fromLeft); + + const nodesToBeRemoved: Array = []; + const tokensToBeRemoved: Array> = []; const toBeMovedToFromParents: Array = []; const latestCreatedAtMap = new Map(); this.traverseInPosRange( @@ -785,16 +800,10 @@ export class CRDTTree extends CRDTGCElement { fromLeft, toParent, toLeft, - (node, contain) => { - // NOTE(hackerwins): If the node overlaps as a closing tag with the - // range then we need to keep the node. - if (!node.isText && contain == TagContained.Closing) { - return; - } - - // NOTE(hackerwins): If the node overlaps as an opening tag with the + ([node, tokenType], ended) => { + // NOTE(hackerwins): If the node overlaps as a start tag with the // range then we need to move the remaining children to fromParent. - if (!node.isText && contain == TagContained.Opening) { + if (tokenType === TokenType.Start && !ended) { // TODO(hackerwins): Define more clearly merge-able rules // between two parents. For now, we only merge two parents are // both element nodes having text children. @@ -804,10 +813,6 @@ export class CRDTTree extends CRDTGCElement { // } for (const child of node.children) { - if (toBeRemoveds.includes(child)) { - continue; - } - toBeMovedToFromParents.push(child); } } @@ -819,7 +824,12 @@ export class CRDTTree extends CRDTGCElement { : InitialTimeTicket : MaxTimeTicket; - if (node.canDelete(editedAt, latestCreatedAt)) { + // NOTE(sejongk): If the node is removable or its parent is going to + // be removed, then this node should be removed. + if ( + node.canDelete(editedAt, latestCreatedAt) || + nodesToBeRemoved.includes(node.parent!) + ) { const latestCreatedAt = latestCreatedAtMap.get(actorID); const createdAt = node.getCreatedAt(); @@ -827,29 +837,25 @@ export class CRDTTree extends CRDTGCElement { latestCreatedAtMap.set(actorID, createdAt); } - toBeRemoveds.push(node); + // NOTE(hackerwins): If the node overlaps as an end token with the + // range then we need to keep the node. + if (tokenType === TokenType.Text || tokenType === TokenType.Start) { + nodesToBeRemoved.push(node); + } + tokensToBeRemoved.push([node, tokenType]); } }, ); - // TODO(hackerwins): If concurrent deletion happens, we need to seperate the + // NOTE(hackerwins): If concurrent deletion happens, we need to separate the // range(from, to) into multiple ranges. - const changes: Array = []; - changes.push({ - type: TreeChangeType.Content, - from: this.toIndex(fromParent, fromLeft), - to: this.toIndex(toParent, toLeft), - fromPath: this.toPath(fromParent, fromLeft), - toPath: this.toPath(toParent, toLeft), - actor: editedAt.getActorID()!, - value: contents?.length - ? contents.map((content) => toTreeNode(content)) - : undefined, - splitLevel, - }); + const changes: Array = this.makeDeletionChanges( + tokensToBeRemoved, + editedAt, + ); // 02. Delete: delete the nodes that are marked as removed. - for (const node of toBeRemoveds) { + for (const node of nodesToBeRemoved) { node.remove(editedAt); if (node.isRemoved) { this.removedNodeMap.set(node.id.toIDString(), node); @@ -858,7 +864,9 @@ export class CRDTTree extends CRDTGCElement { // 03. Merge: move the nodes that are marked as moved. for (const node of toBeMovedToFromParents) { - fromParent.append(node); + if (!node.removedAt) { + fromParent.append(node); + } } // 04. Split: split the element nodes for the given split level. @@ -872,12 +880,20 @@ export class CRDTTree extends CRDTGCElement { parent = parent.parent!; splitCount++; } + changes.push({ + type: TreeChangeType.Content, + from: fromIdx, + to: fromIdx, + fromPath, + toPath: fromPath, + actor: editedAt.getActorID()!, + }); } // 05. Insert: insert the given nodes at the given position. if (contents?.length) { + const aliveContents: Array = []; let leftInChildren = fromLeft; // tree - for (const content of contents) { // 05-1. Insert the content nodes to the tree. if (leftInChildren === fromParent) { @@ -899,6 +915,26 @@ export class CRDTTree extends CRDTGCElement { this.nodeMapByID.put(node.id, node); }); + + if (!content.isRemoved) { + aliveContents.push(content); + } + } + if (aliveContents.length) { + const value = aliveContents.map((content) => toTreeNode(content)); + if (changes.length && changes[changes.length - 1].from === fromIdx) { + changes[changes.length - 1].value = value; + } else { + changes.push({ + type: TreeChangeType.Content, + from: fromIdx, + to: fromIdx, + fromPath, + toPath: fromPath, + actor: editedAt.getActorID()!, + value, + }); + } } } @@ -1195,11 +1231,11 @@ export class CRDTTree extends CRDTGCElement { fromLeft: CRDTTreeNode, toParent: CRDTTreeNode, toLeft: CRDTTreeNode, - callback: (node: CRDTTreeNode, contain: TagContained) => void, + callback: (token: TreeToken, ended: boolean) => void, ): void { const fromIdx = this.toIndex(fromParent, fromLeft); const toIdx = this.toIndex(toParent, toLeft); - return this.indexTree.nodesBetween(fromIdx, toIdx, callback); + return this.indexTree.tokensBetween(fromIdx, toIdx, callback); } /** @@ -1251,4 +1287,127 @@ export class CRDTTree extends CRDTGCElement { offset, }; } + + /** + * `makeDeletionChanges` converts nodes to be deleted to deletion changes. + */ + private makeDeletionChanges( + candidates: Array>, + editedAt: TimeTicket, + ): Array { + const changes: Array = []; + const ranges: Array>> = []; + + // Generate ranges by accumulating consecutive nodes. + let start = null; + let end = null; + for (let i = 0; i < candidates.length; i++) { + const cur = candidates[i]; + const next = candidates[i + 1]; + if (!start) { + start = cur; + } + end = cur; + + const rightToken = this.findRightToken(cur); + if ( + !rightToken || + !next || + rightToken[0] !== next[0] || + rightToken[1] !== next[1] + ) { + ranges.push([start, end]); + start = null; + end = null; + } + } + + // Convert each range to a deletion change. + for (const range of ranges) { + const [start, end] = range; + const [fromLeft, fromLeftTokenType] = this.findLeftToken(start); + const [toLeft, toLeftTokenType] = end; + const fromParent = + fromLeftTokenType === TokenType.Start ? fromLeft : fromLeft.parent!; + const toParent = + toLeftTokenType === TokenType.Start ? toLeft : toLeft.parent!; + + const fromIdx = this.toIndex(fromParent, fromLeft); + const toIdx = this.toIndex(toParent, toLeft); + if (fromIdx < toIdx) { + // When the range is overlapped with the previous one, compact them. + if (changes.length > 0 && fromIdx === changes[changes.length - 1].to) { + changes[changes.length - 1].to = toIdx; + changes[changes.length - 1].toPath = this.toPath(toParent, toLeft); + } else { + changes.push({ + type: TreeChangeType.Content, + from: fromIdx, + to: toIdx, + fromPath: this.toPath(fromParent, fromLeft), + toPath: this.toPath(toParent, toLeft), + actor: editedAt.getActorID()!, + }); + } + } + } + return changes; + } + + /** + * `findRightToken` returns the token to the right of the given token in the tree. + */ + private findRightToken([ + node, + tokenType, + ]: TreeToken): TreeToken { + if (tokenType === TokenType.Start) { + const children = node.allChildren; + if (children.length > 0) { + return [ + children[0], + children[0].isText ? TokenType.Text : TokenType.Start, + ]; + } + return [node, TokenType.End]; + } + + const parent = node.parent!; + const siblings = parent.allChildren; + const offset = siblings.indexOf(node); + if (parent && offset === siblings.length - 1) { + return [parent, TokenType.End]; + } + + const next = siblings[offset + 1]; + return [next, next.isText ? TokenType.Text : TokenType.Start]; + } + + /** + * `findLeftToken` returns the token to the left of the given token in the tree. + */ + private findLeftToken([ + node, + tokenType, + ]: TreeToken): TreeToken { + if (tokenType === TokenType.End) { + const children = node.allChildren; + if (children.length > 0) { + const lastChild = children[children.length - 1]; + return [lastChild, lastChild.isText ? TokenType.Text : TokenType.End]; + } + + return [node, TokenType.Start]; + } + + const parent = node.parent!; + const siblings = parent.allChildren; + const offset = siblings.indexOf(node); + if (parent && offset === 0) { + return [parent, TokenType.Start]; + } + + const prev = siblings[offset - 1]; + return [prev, prev.isText ? TokenType.Text : TokenType.End]; + } } diff --git a/src/util/index_tree.ts b/src/util/index_tree.ts index e09ce495a..6d1646ce5 100644 --- a/src/util/index_tree.ts +++ b/src/util/index_tree.ts @@ -498,27 +498,46 @@ function ancestorOf>(ancestor: T, node: T): boolean { return false; } -// TagContained represents whether the opening or closing tag of a element is selected. -export enum TagContained { - // All represents that both opening and closing tag of a element are selected. - All = 'All', - // Opening represents that only the opening tag is selected. - Opening = 'Opening', - // Closing represents that only the closing tag is selected. - Closing = 'Closing', +/** + * `TokenType` represents the type of token in XML representation. + */ +export enum TokenType { + /** + * `Start` represents that the start token type. + */ + Start = 'Start', + + /** + * `End` represents that the end token type. + */ + End = 'End', + + /** + * `Text` represents that the text token type. + */ + Text = 'Text', } /** - * `nodesBetween` iterates the nodes between the given range. + * `TreeToken` represents the token of the tree in XML representation. + */ +export type TreeToken = [T, TokenType]; + +/** + * `tokensBetween` iterates the tokens between the given range. + * + * For example, if the tree is

abc

, the tokens are + * [p, Start], [i, Start], [abc, Text], [i, End], [p, End]. + * * If the given range is collapsed, the callback is not called. - * It traverses the tree with postorder traversal. + * It traverses the tree based on the concept of token. * NOTE(sejongk): Nodes should not be removed in callback, because it leads wrong behaviors. */ -function nodesBetween>( +function tokensBetween>( root: T, from: number, to: number, - callback: (node: T, contain: TagContained) => void, + callback: (token: TreeToken, ended: boolean) => void, ) { if (from > to) { throw new Error(`from is greater than to: ${from} > ${to}`); @@ -546,25 +565,24 @@ function nodesBetween>( const fromChild = child.isText ? from - pos : from - pos - 1; const toChild = child.isText ? to - pos : to - pos - 1; - nodesBetween( + // If the range spans outside the child, + // the callback is called with the child. + const startContained = !child.isText && fromChild < 0; + const endContained = !child.isText && toChild > child.size; + if (child.isText || startContained) { + callback( + [child, child.isText ? TokenType.Text : TokenType.Start], + endContained, + ); + } + tokensBetween( child, Math.max(0, fromChild), Math.min(toChild, child.size), callback, ); - - // If the range spans outside the child, - // the callback is called with the child. - if (fromChild < 0 || toChild > child.size || child.isText) { - let contain: TagContained; - if ((fromChild < 0 && toChild > child.size) || child.isText) { - contain = TagContained.All; - } else if (fromChild < 0) { - contain = TagContained.Opening; - } else { - contain = TagContained.Closing; - } - callback(child, contain); + if (endContained) { + callback([child, TokenType.End], endContained); } } pos += child.paddedSize; @@ -738,14 +756,14 @@ export class IndexTree> { } /** - * `nodeBetween` returns the nodes between the given range. + * `tokensBetween` returns the tokens between the given range. */ - nodesBetween( + tokensBetween( from: number, to: number, - callback: (node: T, contain: TagContained) => void, + callback: (token: TreeToken, ended: boolean) => void, ): void { - nodesBetween(this.root, from, to, callback); + tokensBetween(this.root, from, to, callback); } /** diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index 8a798ae3c..5ad2e736a 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -21,6 +21,7 @@ import { withTwoClientsAndDocuments, } from '@yorkie-js-sdk/test/integration/integration_helper'; import { TreeEditOpInfo } from '@yorkie-js-sdk/src/document/operation/operation'; +import { Document } from '@yorkie-js-sdk/src/document/document'; describe('Tree', () => { it('Can be created', function ({ task }) { @@ -3594,3 +3595,343 @@ describe('testing edge cases', () => { }, task.name); }); }); + +describe('TreeChange Generation', () => { + it('Concurrent delete and delete', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], + }); + assert.equal(root.t.toXML(), /*html*/ `

ab

`); + }); + await c1.sync(); + await c2.sync(); + + const [ops1, ops2] = subscribeDocs(d1, d2); + + d1.update((root) => root.t.edit(0, 4)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); + + d2.update((root) => root.t.edit(1, 2)); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

b

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + + assert.deepEqual( + ops1.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 0, + to: 4, + value: undefined, + } as any, + ], + ); + + assert.deepEqual( + ops2.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 1, + to: 2, + value: undefined, + } as any, + { + type: 'tree-edit', + from: 0, + to: 3, + value: undefined, + } as any, + ], + ); + }, task.name); + }); + + it('Concurrent delete and insert', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], + }); + assert.equal(root.t.toXML(), /*html*/ `

ab

`); + }); + await c1.sync(); + await c2.sync(); + + const [ops1, ops2] = subscribeDocs(d1, d2); + + d1.update((root) => root.t.edit(1, 3)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

`); + + d2.update((root) => root.t.edit(2, 2, { type: 'text', value: 'c' })); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

acb

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + + assert.deepEqual( + ops1.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 1, + to: 3, + value: undefined, + } as any, + { + type: 'tree-edit', + from: 1, + to: 1, + value: [{ type: 'text', value: 'c' }], + } as any, + ], + ); + + assert.deepEqual( + ops2.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 2, + to: 2, + value: [{ type: 'text', value: 'c' }], + } as any, + { + type: 'tree-edit', + from: 1, + to: 2, + value: undefined, + } as any, + { + type: 'tree-edit', + from: 3, + to: 4, + value: undefined, + } as any, + ], + ); + }, task.name); + }); + + it('Concurrent delete and insert when parent removed', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [{ type: 'p', children: [{ type: 'text', value: 'ab' }] }], + }); + assert.equal(root.t.toXML(), /*html*/ `

ab

`); + }); + await c1.sync(); + await c2.sync(); + + const [ops1, ops2] = subscribeDocs(d1, d2); + + d1.update((root) => root.t.edit(0, 4)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ ``); + + d2.update((root) => root.t.edit(2, 2, { type: 'text', value: 'c' })); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

acb

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + + assert.deepEqual( + ops1.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 0, + to: 4, + value: undefined, + } as any, + ], + ); + + assert.deepEqual( + ops2.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 2, + to: 2, + value: [{ type: 'text', value: 'c' }], + } as any, + { + type: 'tree-edit', + from: 0, + to: 5, + value: undefined, + } as any, + ], + ); + }, task.name); + }); + + it('Concurrent delete with contents and insert', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [{ type: 'p', children: [{ type: 'text', value: 'a' }] }], + }); + assert.equal(root.t.toXML(), /*html*/ `

a

`); + }); + await c1.sync(); + await c2.sync(); + + const [ops1, ops2] = subscribeDocs(d1, d2); + + d1.update((root) => root.t.edit(1, 2, { type: 'text', value: 'b' })); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

b

`); + + d2.update((root) => root.t.edit(2, 2, { type: 'text', value: 'c' })); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ac

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + + assert.deepEqual( + ops1.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 1, + to: 2, + value: [{ type: 'text', value: 'b' }], + } as any, + { + type: 'tree-edit', + from: 2, + to: 2, + value: [{ type: 'text', value: 'c' }], + } as any, + ], + ); + + assert.deepEqual( + ops2.map((it) => { + return { + type: it.type, + from: it.from, + to: it.to, + value: it.value, + }; + }), + [ + { + type: 'tree-edit', + from: 2, + to: 2, + value: [{ type: 'text', value: 'c' }], + } as any, + { + type: 'tree-edit', + from: 1, + to: 2, + value: [{ type: 'text', value: 'b' }], + } as any, + ], + ); + }, task.name); + }); +}); + +function subscribeDocs( + d1: Document<{ t: Tree }>, + d2: Document<{ t: Tree }>, +): [Array, Array] { + const ops1: Array = []; + const ops2: Array = []; + + d1.subscribe('$.t', (event) => { + if (event.type === 'local-change' || event.type === 'remote-change') { + const { operations } = event.value; + + ops1.push( + ...(operations.filter( + (op) => op.type === 'tree-edit', + ) as Array), + ); + } + }); + + d2.subscribe('$.t', (event) => { + if (event.type === 'local-change' || event.type === 'remote-change') { + const { operations } = event.value; + + ops2.push( + ...(operations.filter( + (op) => op.type === 'tree-edit', + ) as Array), + ); + } + }); + + return [ops1, ops2]; +} diff --git a/test/unit/util/index_tree_test.ts b/test/unit/util/index_tree_test.ts index 6497a0b69..eecddd1b8 100644 --- a/test/unit/util/index_tree_test.ts +++ b/test/unit/util/index_tree_test.ts @@ -28,24 +28,24 @@ import { */ function toDiagnostic(node: CRDTTreeNode): string { if (node.isText) { - return `${node.type}.${node.value}`; + return `${node.value}`; } return node.type; } /** - * `betweenEqual` is a helper function that checks the nodes between the given + * `tokensBetweenEqual` is a helper function that checks the tokens between the given * indexes. */ -function nodesBetweenEqual( +function tokensBetweenEqual( tree: IndexTree, from: number, to: number, expected: Array, ) { const actual: Array = []; - tree.nodesBetween(from, to, (node, contain) => { - actual.push(`${toDiagnostic(node)}:${contain}`); + tree.tokensBetween(from, to, ([node, tokenType]) => { + actual.push(`${toDiagnostic(node)}:${tokenType}`); return true; }); assert.deepEqual(actual, expected); @@ -66,17 +66,17 @@ describe('IndexTree', function () { let pos = tree.findTreePos(0); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['r', 0]); pos = tree.findTreePos(1); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.hello', 0]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['hello', 0]); pos = tree.findTreePos(6); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.hello', 5]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['hello', 5]); pos = tree.findTreePos(6, false); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['p', 1]); pos = tree.findTreePos(7); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['r', 1]); pos = tree.findTreePos(8); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.world', 0]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['world', 0]); pos = tree.findTreePos(13); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.world', 5]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['world', 5]); pos = tree.findTreePos(14); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['r', 2]); }); @@ -119,12 +119,12 @@ describe('IndexTree', function () { const nodeAB = tree.findTreePos(3, true).node; const nodeCD = tree.findTreePos(7, true).node; - assert.equal(toDiagnostic(nodeAB), 'text.ab'); - assert.equal(toDiagnostic(nodeCD), 'text.cd'); + assert.equal(toDiagnostic(nodeAB), 'ab'); + assert.equal(toDiagnostic(nodeCD), 'cd'); assert.equal(findCommonAncestor(nodeAB, nodeCD)!.type, 'p'); }); - it('Can traverse nodes between two given positions', function () { + it('Can traverse tokens between two given positions', function () { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 //

a b

c d e

f g

const tree = buildIndexTree({ @@ -142,23 +142,19 @@ describe('IndexTree', function () { ], }); - nodesBetweenEqual(tree, 2, 11, [ - 'text.b:All', - 'p:Closing', - 'text.cde:All', - 'p:All', - 'text.fg:All', - 'p:Opening', + tokensBetweenEqual(tree, 2, 11, [ + 'b:Text', + 'p:End', + 'p:Start', + 'cde:Text', + 'p:End', + 'p:Start', + 'fg:Text', ]); - nodesBetweenEqual(tree, 2, 6, [ - 'text.b:All', - 'p:Closing', - 'text.cde:All', - 'p:Opening', - ]); - nodesBetweenEqual(tree, 0, 1, ['p:Opening']); - nodesBetweenEqual(tree, 3, 4, ['p:Closing']); - nodesBetweenEqual(tree, 3, 5, ['p:Closing', 'p:Opening']); + tokensBetweenEqual(tree, 2, 6, ['b:Text', 'p:End', 'p:Start', 'cde:Text']); + tokensBetweenEqual(tree, 0, 1, ['p:Start']); + tokensBetweenEqual(tree, 3, 4, ['p:End']); + tokensBetweenEqual(tree, 3, 5, ['p:End', 'p:Start']); }); it('Can convert index to pos', function () { @@ -222,40 +218,40 @@ describe('IndexTree', function () { assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['root', 0]); pos = tree.pathToTreePos([0, 0]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.a', 0]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['a', 0]); pos = tree.pathToTreePos([0, 1]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.a', 1]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['a', 1]); pos = tree.pathToTreePos([0, 2]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.b', 1]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['b', 1]); pos = tree.pathToTreePos([1]); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['root', 1]); pos = tree.pathToTreePos([1, 0]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.cde', 0]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['cde', 0]); pos = tree.pathToTreePos([1, 1]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.cde', 1]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['cde', 1]); pos = tree.pathToTreePos([1, 2]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.cde', 2]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['cde', 2]); pos = tree.pathToTreePos([1, 3]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.cde', 3]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['cde', 3]); pos = tree.pathToTreePos([2]); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['root', 2]); pos = tree.pathToTreePos([2, 0]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.fg', 0]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['fg', 0]); pos = tree.pathToTreePos([2, 1]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.fg', 1]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['fg', 1]); pos = tree.pathToTreePos([2, 2]); - assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['text.fg', 2]); + assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['fg', 2]); pos = tree.pathToTreePos([3]); assert.deepEqual([toDiagnostic(pos.node), pos.offset], ['root', 3]); From a882a6806af8dc495eef3d1ef2e32d367d2333ce Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Fri, 5 Jan 2024 20:04:12 +0900 Subject: [PATCH 26/48] Update CHANGELOG.md for v0.4.12 (#718) --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a341fe0d1..31cd596b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +## [0.4.12] - 2024-01-05 + +### Added +* Add concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/710 + +### Fixed +* Generate correct TreeChange in concurrent edits by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/712 +* Add forced sync when switching to realtime mode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/713 +* Fix `getGarbageLen` to retrun correct size by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/714 +* Prevent deregisterElement from deregistering twice in nested object by @justiceHui in https://github.com/yorkie-team/yorkie-js-sdk/pull/716 + ## [0.4.11] - 2023-12-18 ### Added diff --git a/package.json b/package.json index 5071349da..db53d842e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.11", + "version": "0.4.12", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index 7ec424e0c..350a37345 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.11", + "version": "0.4.12", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 7e339b003450f8f18af574cf6f41c9882a31ff95 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 8 Jan 2024 12:20:44 +0900 Subject: [PATCH 27/48] Fix invalid tree conversion (#719) A script error occurred when creating a snapshot due to a typo in the converter during migrating to ConnectRPC. https://github.com/yorkie-team/yorkie-js-sdk/pull/698 This commit fixes the typo. --- src/api/converter.ts | 6 +++--- test/integration/gc_test.ts | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/api/converter.ts b/src/api/converter.ts index b0fab299f..2b9892568 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -1053,11 +1053,11 @@ function fromTreeNode(pbTreeNode: PbTreeNode): CRDTTreeNode { } if (pbTreeNode.insPrevId) { - node.insPrevID = fromTreeNodeID(pbTreeNode.insPrevId!); + node.insPrevID = fromTreeNodeID(pbTreeNode.insPrevId); } - if (pbTreeNode.insPrevId) { - node.insNextID = fromTreeNodeID(pbTreeNode.insNextId!); + if (pbTreeNode.insNextId) { + node.insNextID = fromTreeNodeID(pbTreeNode.insNextId); } node.removedAt = fromTimeTicket(pbTreeNode.removedAt); diff --git a/test/integration/gc_test.ts b/test/integration/gc_test.ts index ec2ded131..90a53ace6 100644 --- a/test/integration/gc_test.ts +++ b/test/integration/gc_test.ts @@ -114,7 +114,9 @@ describe('Garbage Collection', function () { assert.equal(root, clone); }); - it('getGarbageLen should return the actual number of elements garbage-collected', async function ({ task }) { + it('getGarbageLen should return the actual number of elements garbage-collected', async function ({ + task, + }) { type TestDoc = { point?: { x?: number; y?: number } }; const docKey = toDocKey(`${task.name}-${new Date().getTime()}`); const doc1 = new yorkie.Document(docKey); From 41f31fc4f2b00a447c0a8f2c265b51e6bcacce9a Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 8 Jan 2024 13:55:57 +0900 Subject: [PATCH 28/48] Update CHANGELOG.md for v0.4.13-rc (#720) --- CHANGELOG.md | 3 +++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31cd596b2..91240dbcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +### Fixed +* Fix invalid tree conversion by @hackerwins, @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/719 + ## [0.4.12] - 2024-01-05 ### Added diff --git a/package.json b/package.json index db53d842e..cc35eb336 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.12", + "version": "0.4.13-rc", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index 350a37345..291f0dffe 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.12", + "version": "0.4.13-rc", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 97aba9eecd2b79ab6b5f9b88a53324e3e96f21fd Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Tue, 9 Jan 2024 19:48:05 +0900 Subject: [PATCH 29/48] Update examples version to v0.4.12 (#722) --- examples/nextjs-scheduler/package.json | 2 +- examples/profile-stack/package.json | 2 +- examples/react-tldraw/package.json | 2 +- examples/react-todomvc/package.json | 2 +- examples/simultaneous-cursors/package.json | 2 +- examples/vanilla-codemirror6/package.json | 2 +- examples/vanilla-quill/package.json | 2 +- examples/vuejs-kanban/package.json | 2 +- package-lock.json | 26 +++++++++++----------- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/nextjs-scheduler/package.json b/examples/nextjs-scheduler/package.json index a3bb194ae..a16620007 100644 --- a/examples/nextjs-scheduler/package.json +++ b/examples/nextjs-scheduler/package.json @@ -13,7 +13,7 @@ "react": "18.2.0", "react-calendar": "^4.6.0", "react-dom": "18.2.0", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/node": "20.4.2", diff --git a/examples/profile-stack/package.json b/examples/profile-stack/package.json index cc6a35970..806578f86 100644 --- a/examples/profile-stack/package.json +++ b/examples/profile-stack/package.json @@ -12,6 +12,6 @@ "vite": "^3.2.7" }, "dependencies": { - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" } } diff --git a/examples/react-tldraw/package.json b/examples/react-tldraw/package.json index f3b9fdb41..2545beef4 100644 --- a/examples/react-tldraw/package.json +++ b/examples/react-tldraw/package.json @@ -16,7 +16,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "unique-names-generator": "^4.7.1", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/lodash": "^4.14.198", diff --git a/examples/react-todomvc/package.json b/examples/react-todomvc/package.json index c4edac97f..6a8aab3c3 100644 --- a/examples/react-todomvc/package.json +++ b/examples/react-todomvc/package.json @@ -13,7 +13,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "todomvc-app-css": "^2.4.2", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/react": "^18.0.24", diff --git a/examples/simultaneous-cursors/package.json b/examples/simultaneous-cursors/package.json index ce839aa71..be2184430 100644 --- a/examples/simultaneous-cursors/package.json +++ b/examples/simultaneous-cursors/package.json @@ -11,7 +11,7 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/react": "^18.0.37", diff --git a/examples/vanilla-codemirror6/package.json b/examples/vanilla-codemirror6/package.json index 991e35a02..aa9495cae 100644 --- a/examples/vanilla-codemirror6/package.json +++ b/examples/vanilla-codemirror6/package.json @@ -20,6 +20,6 @@ "@codemirror/state": "^6.1.2", "@codemirror/view": "^6.3.1", "codemirror": "^6.0.1", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" } } diff --git a/examples/vanilla-quill/package.json b/examples/vanilla-quill/package.json index f314e1015..081e792d9 100644 --- a/examples/vanilla-quill/package.json +++ b/examples/vanilla-quill/package.json @@ -20,6 +20,6 @@ "quill-cursors": "^4.0.0", "quill-delta": "^5.0.0", "short-unique-id": "^4.4.4", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" } } diff --git a/examples/vuejs-kanban/package.json b/examples/vuejs-kanban/package.json index 0e73fcd15..888c15bfc 100644 --- a/examples/vuejs-kanban/package.json +++ b/examples/vuejs-kanban/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "vue": "^3.2.41", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.2", diff --git a/package-lock.json b/package-lock.json index 920a39146..63789cfaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "yorkie-js-sdk", - "version": "0.4.10", + "version": "0.4.13-rc", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "yorkie-js-sdk", - "version": "0.4.10", + "version": "0.4.13-rc", "license": "Apache-2.0", "workspaces": [ "examples/*", @@ -72,7 +72,7 @@ "react": "18.2.0", "react-calendar": "^4.6.0", "react-dom": "18.2.0", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/node": "20.4.2", @@ -114,7 +114,7 @@ "examples/profile-stack": { "version": "0.0.0", "dependencies": { - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "vite": "^3.2.7" @@ -179,7 +179,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "unique-names-generator": "^4.7.1", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/lodash": "^4.14.198", @@ -247,7 +247,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "todomvc-app-css": "^2.4.2", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/react": "^18.0.24", @@ -311,7 +311,7 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/react": "^18.0.37", @@ -347,7 +347,7 @@ "@codemirror/state": "^6.1.2", "@codemirror/view": "^6.3.1", "codemirror": "^6.0.1", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "typescript": "^4.6.4", @@ -411,7 +411,7 @@ "quill-cursors": "^4.0.0", "quill-delta": "^5.0.0", "short-unique-id": "^4.4.4", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/color-hash": "^1.0.2", @@ -485,7 +485,7 @@ "version": "0.0.0", "dependencies": { "vue": "^3.2.41", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.2", @@ -12955,9 +12955,9 @@ } }, "node_modules/yorkie-js-sdk": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.7.tgz", - "integrity": "sha512-bUe2f11TTAxV5nsSvozFNGiiHiVhZy03IGbHWwUxsuGa/JluGQOhlqDuyPLEmaPe62YRJlbbBXJ4WAczTjObaA==", + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.12.tgz", + "integrity": "sha512-V0NM423hmJ5NaFDRJgEgnWgr1Nd8rqy7SZoZ3uu5TBJIlDgbX6HOEjPWWUopnBdD/WFAeiycOYAbNFD6sdHt8A==", "dependencies": { "@types/google-protobuf": "^3.15.5", "@types/long": "^4.0.1", From d6235503fb788df7910b8420bb203d1be7a4e348 Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:39:29 +0900 Subject: [PATCH 30/48] Complement concurrent editing test cases in Tree (#721) Co-authored-by: Youngteac Hong --- test/integration/tree_test.ts | 123 +++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 23 deletions(-) diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index 5ad2e736a..890af8e30 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -534,7 +534,7 @@ describe('Tree', () => { }, task.name); }); - it('Get correct range from index', function ({ task }) { + it('Should return correct range from index', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); @@ -572,7 +572,7 @@ describe('Tree', () => { assert.deepEqual(tree.posRangeToIndexRange(range), [5, 7]); }); - it('Get correct range from path', function ({ task }) { + it('Should return correct range from path', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); @@ -781,7 +781,7 @@ describe('Tree.edit', function () { }); }); - it('Detecting error for empty text', function ({ task }) { + it('Should detect error for empty text', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); doc.update((root) => { @@ -807,7 +807,7 @@ describe('Tree.edit', function () { }, 'text node cannot have empty value'); }); - it('Detecting error for mixed type insertion', function ({ task }) { + it('Should detect error for mixed type insertion', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); doc.update((root) => { @@ -833,7 +833,7 @@ describe('Tree.edit', function () { }, 'element node and text node cannot be passed together'); }); - it('Detecting correct error order [1]', function ({ task }) { + it('Should detect correct error order [1]', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); doc.update((root) => { @@ -865,7 +865,7 @@ describe('Tree.edit', function () { }, 'element node and text node cannot be passed together'); }); - it('Detecting correct error order [2]', function ({ task }) { + it('Should detect correct error order [2]', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); doc.update((root) => { @@ -891,7 +891,7 @@ describe('Tree.edit', function () { }, 'text node cannot have empty value'); }); - it('Detecting correct error order [3]', function ({ task }) { + it('Should detect correct error order [3]', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); doc.update((root) => { @@ -917,7 +917,7 @@ describe('Tree.edit', function () { }, 'element node and text node cannot be passed together'); }); - it('delete nodes in a multi-level range test', function ({ task }) { + it('Can delete nodes in a multi-level range', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); doc.update((root) => { @@ -1129,7 +1129,7 @@ describe('Tree.style', function () { }, task.name); }); - it('style node with element attributes test', function ({ task }) { + it('Can style node with element attributes test', function ({ task }) { const key = toDocKey(`${task.name}-${new Date().getTime()}`); const doc = new yorkie.Document<{ t: Tree }>(key); @@ -1189,7 +1189,7 @@ describe('Tree.style', function () { }); }); -describe('Concurrent editing, overlapping range', () => { +describe('Tree.edit(concurrent overlapping range)', () => { it('Can concurrently delete overlapping elements', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { @@ -1290,7 +1290,9 @@ describe('Concurrent editing, overlapping range', () => { }, task.name); }); - it.skip('overlapping-merge-and-delete', async function ({ task }) { + it.skip('overlapping-merge-and-delete-element-node', async function ({ + task, + }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -1318,9 +1320,44 @@ describe('Concurrent editing, overlapping range', () => { assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

`); }, task.name); }); + + it.skip('overlapping-merge-and-delete-text-nodes', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'bcde' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

bcde

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

bcde

`, + ); + + d1.update((r) => r.t.edit(2, 4)); + d2.update((r) => r.t.edit(4, 6)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

abcde

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

de

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ade

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ade

`); + }, task.name); + }); }); -describe('Concurrent editing, contained range', () => { +describe('Tree.edit(concurrent, contained range)', () => { it('Can concurrently insert and delete contained elements of the same depth', async function ({ task, }) { @@ -1870,7 +1907,9 @@ describe('Concurrent editing, contained range', () => { }, task.name); }); - it('contained-merge-and-merge', async function ({ task }) { + it('contained-merge-and-merge-at-different-levels', async function ({ + task, + }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -1917,6 +1956,44 @@ describe('Concurrent editing, contained range', () => { }, task.name); }); + it.skip('contained-merge-and-merge-at-the-same-level', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'r', + children: [ + { type: 'p', children: [{ type: 'text', value: 'a' }] }, + { type: 'p', children: [{ type: 'text', value: 'b' }] }, + { type: 'p', children: [{ type: 'text', value: 'c' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

a

b

c

`, + ); + + d1.update((r) => r.t.edit(2, 7)); + d2.update((r) => r.t.edit(5, 7)); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ac

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

a

bc

`); + + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ac

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ac

`); + }, task.name); + }); + it.skip('contained-merge-and-insert', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { @@ -2126,7 +2203,7 @@ describe('Concurrent editing, contained range', () => { }); }); -describe('Concurrent editing, side by side range', () => { +describe('Tree.edit(concurrent, side by side range)', () => { it('Can concurrently insert side by side elements (left)', async function ({ task, }) { @@ -2897,7 +2974,7 @@ describe('Concurrent editing, side by side range', () => { }); }); -describe('Concurrent editing, complex cases', () => { +describe('Tree.edit(concurrent, complex cases)', () => { it('Can delete text content anchored to another concurrently', async function ({ task, }) { @@ -3271,7 +3348,7 @@ describe('Concurrent editing, complex cases', () => { }); }); -describe('testing edge cases', () => { +describe('Tree(edge cases)', () => { it('Can delete very first text when there is tombstone in front of target text', function ({ task, }) { @@ -3357,7 +3434,7 @@ describe('testing edge cases', () => { }); }); - it('split link can transmitted through rpc', async function ({ task }) { + it('Can split link can transmitted through rpc', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -3402,7 +3479,7 @@ describe('testing edge cases', () => { }, task.name); }); - it('can calculate size of index tree correctly', async function ({ task }) { + it('Can calculate size of index tree correctly', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -3437,7 +3514,7 @@ describe('testing edge cases', () => { }, task.name); }); - it('can split and merge with empty paragraph: left', async function ({ + it('Can split and merge with empty paragraph: left', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { @@ -3471,7 +3548,7 @@ describe('testing edge cases', () => { }, task.name); }); - it('can split and merge with empty paragraph: right', async function ({ + it('Can split and merge with empty paragraph: right', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { @@ -3505,7 +3582,7 @@ describe('testing edge cases', () => { }, task.name); }); - it('can split and merge with empty paragraph and multiple split level: left', async function ({ + it('Can split and merge with empty paragraph and multiple split level: left', async function ({ task, }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { @@ -3550,7 +3627,7 @@ describe('testing edge cases', () => { }, task.name); }); - it('split at the same offset multiple times', async function ({ task }) { + it('Can split at the same offset multiple times', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { root.t = new Tree({ @@ -3596,7 +3673,7 @@ describe('testing edge cases', () => { }); }); -describe('TreeChange Generation', () => { +describe('TreeChange', () => { it('Concurrent delete and delete', async function ({ task }) { await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { d1.update((root) => { From 639bb77a7234367af3ad1fb1d2c260ae23a6790d Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Wed, 10 Jan 2024 15:44:06 +0900 Subject: [PATCH 31/48] Update protobuf description in CONTRIBUTING.md (#724) --- CONTRIBUTING.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b88557e22..fc0b84b0d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,9 +49,9 @@ $ npm install $ npm run build ``` -For generating proto messages and the service client stub classes with protoc and the protoc-gen-grpc-web. +To generate proto messages, we use protoc-gen-connect-es, which is a code generator plugin for Protocol Buffer compilers, like buf and protoc. It generates both clients and server definitions from Protocol Buffer schema. -How to install protoc-gen-grpc-web: https://github.com/grpc/grpc-web#code-generator-plugin +For more details, see [@connectrpc/protoc-gen-connect-es](https://github.com/connectrpc/connect-es/tree/main/packages/protoc-gen-connect-es). ```bash # generate proto messages and the service client stub classes @@ -83,6 +83,7 @@ $ docker-compose -f docker/docker-compose.yml up --build -d ``` To print specific console logs, delete the line `return false` in the `onConsoleLog()` function within [`vitest.config.ts`](https://github.com/yorkie-team/yorkie-js-sdk/blob/main/vitest.config.ts#L16). + ```ts export default defineConfig({ test: { @@ -101,11 +102,11 @@ export default defineConfig({ }, plugins: [tsconfigPaths()], }); - ``` -To run only specific suites or tests, use `.only` and execute the following command with the path to the desired test file. +To run only specific suites or tests, use `.only` and execute the following command with the path to the desired test file. Refer to [Test Filtering](https://vitest.dev/guide/filtering#selecting-suites-and-tests-to-run) in `vitest` for more details: + ```bash $ npm run test {test file path} # e.g. npm run test integration/tree_test.ts ``` From 2f951cc7e4b5525fb4880f27fca9f4e3f901e2b2 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:44:22 +0900 Subject: [PATCH 32/48] Implement devtools chrome extension (#717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A browser extension that helps you debug Yorkie. With this extension, you can access the 🐶 Yorkie panel within the Chrome Developer Tools. Here's an overview of the Key features: Left Tab: Document - Instant access to document keys. - Visualize the rootObject structure for a comprehensive understanding. CRDT insights - Clearly display data types for each CRDTElement using intuitive icons and informative tooltips. - Click on any CRDTElement to unveil datatype-specific details tailored to your debugging needs. View Options - By default, enjoy a JSON view for quick analysis. - Explore tree data types with an interactive graph view, offering a deeper understanding of the data structure. --------- Co-authored-by: Youngteac Hong --- config/webpack.config.js | 1 + examples/nextjs-scheduler/app/page.tsx | 2 +- package-lock.json | 8601 +++++++++++++++-- package.json | 1 + public/devtool/object.js | 16 +- src/devtools/index.ts | 146 + src/devtools/protocol.ts | 109 + src/devtools/types.ts | 95 + src/document/crdt/array.ts | 8 +- src/document/crdt/counter.ts | 4 +- src/document/crdt/element.ts | 2 +- src/document/crdt/object.ts | 8 +- src/document/crdt/primitive.ts | 4 +- src/document/crdt/text.ts | 4 +- src/document/crdt/tree.ts | 51 +- src/document/document.ts | 39 + src/document/json/object.ts | 6 + src/document/json/tree.ts | 14 + src/types/devtools_element.ts | 38 - src/yorkie.ts | 1 + tools/devtools/.gitignore | 33 + tools/devtools/README.md | 18 + tools/devtools/assets/icon.png | Bin 0 -> 2067 bytes tools/devtools/package.json | 35 + tools/devtools/src/content.ts | 54 + .../devtools/src/devtools/components/Code.tsx | 92 + .../src/devtools/components/Detail.tsx | 125 + .../devtools/src/devtools/components/Tree.tsx | 345 + .../src/devtools/contexts/SeletedNode.tsx | 43 + .../src/devtools/contexts/SeletedPresence.tsx | 50 + .../src/devtools/contexts/YorkieSource.tsx | 131 + tools/devtools/src/devtools/icons/index.tsx | 207 + tools/devtools/src/devtools/index.tsx | 30 + tools/devtools/src/devtools/panel/code.css | 41 + tools/devtools/src/devtools/panel/index.html | 13 + tools/devtools/src/devtools/panel/index.tsx | 72 + tools/devtools/src/devtools/panel/styles.css | 337 + tools/devtools/src/devtools/tabs/Document.tsx | 65 + tools/devtools/src/devtools/tabs/Presence.tsx | 53 + tools/devtools/src/popup/index.tsx | 31 + tools/devtools/src/port.ts | 52 + tools/devtools/src/protocol.ts | 193 + tools/devtools/tsconfig.json | 19 + vitest.config.ts | 2 +- 44 files changed, 10242 insertions(+), 949 deletions(-) create mode 100644 src/devtools/index.ts create mode 100644 src/devtools/protocol.ts create mode 100644 src/devtools/types.ts delete mode 100644 src/types/devtools_element.ts create mode 100644 tools/devtools/.gitignore create mode 100644 tools/devtools/README.md create mode 100644 tools/devtools/assets/icon.png create mode 100644 tools/devtools/package.json create mode 100644 tools/devtools/src/content.ts create mode 100644 tools/devtools/src/devtools/components/Code.tsx create mode 100644 tools/devtools/src/devtools/components/Detail.tsx create mode 100644 tools/devtools/src/devtools/components/Tree.tsx create mode 100644 tools/devtools/src/devtools/contexts/SeletedNode.tsx create mode 100644 tools/devtools/src/devtools/contexts/SeletedPresence.tsx create mode 100644 tools/devtools/src/devtools/contexts/YorkieSource.tsx create mode 100644 tools/devtools/src/devtools/icons/index.tsx create mode 100644 tools/devtools/src/devtools/index.tsx create mode 100644 tools/devtools/src/devtools/panel/code.css create mode 100644 tools/devtools/src/devtools/panel/index.html create mode 100644 tools/devtools/src/devtools/panel/index.tsx create mode 100644 tools/devtools/src/devtools/panel/styles.css create mode 100644 tools/devtools/src/devtools/tabs/Document.tsx create mode 100644 tools/devtools/src/devtools/tabs/Presence.tsx create mode 100644 tools/devtools/src/popup/index.tsx create mode 100644 tools/devtools/src/port.ts create mode 100644 tools/devtools/src/protocol.ts create mode 100644 tools/devtools/tsconfig.json diff --git a/config/webpack.config.js b/config/webpack.config.js index fdcc09516..e09a1f70e 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -47,6 +47,7 @@ module.exports = { mode: 'production', optimization: { minimize: false, + nodeEnv: false, }, module: { rules: [ diff --git a/examples/nextjs-scheduler/app/page.tsx b/examples/nextjs-scheduler/app/page.tsx index f0a4aa665..654d2fd26 100644 --- a/examples/nextjs-scheduler/app/page.tsx +++ b/examples/nextjs-scheduler/app/page.tsx @@ -124,7 +124,7 @@ export default function Editor() { }, 'create default content if not exists'); // 04. subscribe doc's change event from local and remote. - doc.subscribe((event) => { + doc.subscribe(() => { callback(doc.getRoot().content); }); diff --git a/package-lock.json b/package-lock.json index 63789cfaa..e0ab01e46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13-rc", + "version": "0.4.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "yorkie-js-sdk", - "version": "0.4.13-rc", + "version": "0.4.12", "license": "Apache-2.0", "workspaces": [ "examples/*", @@ -72,7 +72,7 @@ "react": "18.2.0", "react-calendar": "^4.6.0", "react-dom": "18.2.0", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "@types/node": "20.4.2", @@ -114,7 +114,7 @@ "examples/profile-stack": { "version": "0.0.0", "dependencies": { - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "vite": "^3.2.7" @@ -179,7 +179,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "unique-names-generator": "^4.7.1", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "@types/lodash": "^4.14.198", @@ -247,7 +247,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "todomvc-app-css": "^2.4.2", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "@types/react": "^18.0.24", @@ -311,7 +311,7 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "@types/react": "^18.0.37", @@ -347,7 +347,7 @@ "@codemirror/state": "^6.1.2", "@codemirror/view": "^6.3.1", "codemirror": "^6.0.1", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "typescript": "^4.6.4", @@ -411,7 +411,7 @@ "quill-cursors": "^4.0.0", "quill-delta": "^5.0.0", "short-unique-id": "^4.4.4", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "@types/color-hash": "^1.0.2", @@ -485,7 +485,7 @@ "version": "0.0.0", "dependencies": { "vue": "^3.2.41", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.7" }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.2", @@ -545,7 +545,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -556,7 +555,6 @@ }, "node_modules/@babel/code-frame": { "version": "7.22.13", - "dev": true, "license": "MIT", "dependencies": { "@babel/highlight": "^7.22.13", @@ -568,7 +566,6 @@ }, "node_modules/@babel/code-frame/node_modules/chalk": { "version": "2.4.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -581,7 +578,6 @@ }, "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -589,7 +585,6 @@ }, "node_modules/@babel/compat-data": { "version": "7.22.9", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -597,7 +592,6 @@ }, "node_modules/@babel/core": { "version": "7.22.11", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -626,7 +620,6 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -636,7 +629,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, "dependencies": { "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", @@ -660,7 +652,6 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.22.10", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.9", @@ -675,7 +666,6 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { "version": "5.1.1", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -683,7 +673,6 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -691,14 +680,12 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "version": "3.1.1", - "dev": true, "license": "ISC" }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -707,7 +694,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -718,7 +704,6 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -729,7 +714,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -740,7 +724,6 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.22.9", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.5", @@ -766,7 +749,6 @@ }, "node_modules/@babel/helper-simple-access": { "version": "7.22.5", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -777,7 +759,6 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.22.6", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -788,7 +769,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.22.5", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -798,14 +778,12 @@ "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.22.5", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -813,7 +791,6 @@ }, "node_modules/@babel/helpers": { "version": "7.22.11", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.22.5", @@ -826,7 +803,6 @@ }, "node_modules/@babel/highlight": { "version": "7.22.13", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.22.5", @@ -839,7 +815,6 @@ }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -852,7 +827,6 @@ }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -961,7 +935,6 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/parser": "^7.22.15", @@ -975,7 +948,6 @@ "version": "7.23.2", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", @@ -994,7 +966,6 @@ }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -1004,7 +975,6 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", "@babel/helper-validator-identifier": "^7.22.20", @@ -1016,7 +986,6 @@ }, "node_modules/@babel/types/node_modules/to-fast-properties": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -1547,7 +1516,7 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -1558,7 +1527,7 @@ }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1609,7 +1578,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -1625,7 +1593,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "android" @@ -1641,7 +1608,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1657,7 +1623,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1673,7 +1638,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -1689,7 +1653,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -1705,7 +1668,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1721,7 +1683,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1737,7 +1698,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1769,7 +1729,6 @@ "cpu": [ "mips64el" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1785,7 +1744,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1801,7 +1759,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1817,7 +1774,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1833,7 +1789,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1849,7 +1804,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "netbsd" @@ -1865,7 +1819,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "openbsd" @@ -1881,7 +1834,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "sunos" @@ -1897,7 +1849,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1913,7 +1864,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1929,7 +1879,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1973,6 +1922,17 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@expo/spawn-async": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz", + "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==", + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@floating-ui/core": { "version": "0.7.3", "license": "MIT" @@ -2124,6 +2084,95 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -2147,7 +2196,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -2160,7 +2208,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2168,7 +2215,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2176,7 +2222,7 @@ }, "node_modules/@jridgewell/source-map": { "version": "0.3.5", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", @@ -2185,18 +2231,21 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.18", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" + }, "node_modules/@lezer/common": { "version": "1.0.2", "license": "MIT" @@ -2304,6 +2353,89 @@ "@lezer/lr": "^1.0.0" } }, + "node_modules/@ljharb/through": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", + "integrity": "sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@microsoft/api-documenter": { "version": "7.22.33", "dev": true, @@ -2393,6 +2525,91 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/@mischnic/json-sourcemap": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz", + "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/lr": "^1.0.0", + "json5": "^2.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@next/env": { "version": "13.5.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz", @@ -2535,7 +2752,6 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2547,7 +2763,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2555,7 +2770,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -2565,836 +2779,4255 @@ "node": ">= 8" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "dev": true, - "license": "MIT" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/bundler-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.3.tgz", + "integrity": "sha512-JjJK8dq39/UO/MWI/4SCbB1t/qgpQRFnFDetAAAezQ8oN++b24u1fkMDa/xqQGjbuPmGeTds5zxGgYs7id7PYg==", "dependencies": { - "@babel/runtime": "^7.13.10" + "@parcel/diagnostic": "2.9.3", + "@parcel/graph": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.0.2", - "license": "MIT", + "node_modules/@parcel/cache": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.3.tgz", + "integrity": "sha512-Bj/H2uAJJSXtysG7E/x4EgTrE2hXmm7td/bc97K8M9N7+vQjxf7xb0ebgqe84ePVMkj4MVQSMEJkEucXVx4b0Q==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-dialog": "1.0.2", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-slot": "1.0.1" + "@parcel/fs": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/utils": "2.9.3", + "lmdb": "2.7.11" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "@parcel/core": "^2.9.3" } }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/codeframe": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.3.tgz", + "integrity": "sha512-z7yTyD6h3dvduaFoHpNqur74/2yDWL++33rjQjIjCaXREBN6dKHoMGMizzo/i4vbiI1p9dDox2FIDEHCMQxqdA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" + "chalk": "^4.1.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/compressor-raw": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.3.tgz", + "integrity": "sha512-jz3t4/ICMsHEqgiTmv5i1DJva2k5QRpZlBELVxfY+QElJTVe8edKJ0TiKcBxh2hx7sm4aUigGmp7JiqqHRRYmA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/config-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.3.tgz", + "integrity": "sha512-tqN5tF7QnVABDZAu76co5E6N8mA9n8bxiWdK4xYyINYFIEHgX172oRTqXTnhEMjlMrdmASxvnGlbaPBaVnrCTw==", + "dependencies": { + "@parcel/bundler-default": "2.9.3", + "@parcel/compressor-raw": "2.9.3", + "@parcel/namer-default": "2.9.3", + "@parcel/optimizer-css": "2.9.3", + "@parcel/optimizer-htmlnano": "2.9.3", + "@parcel/optimizer-image": "2.9.3", + "@parcel/optimizer-svgo": "2.9.3", + "@parcel/optimizer-swc": "2.9.3", + "@parcel/packager-css": "2.9.3", + "@parcel/packager-html": "2.9.3", + "@parcel/packager-js": "2.9.3", + "@parcel/packager-raw": "2.9.3", + "@parcel/packager-svg": "2.9.3", + "@parcel/reporter-dev-server": "2.9.3", + "@parcel/resolver-default": "2.9.3", + "@parcel/runtime-browser-hmr": "2.9.3", + "@parcel/runtime-js": "2.9.3", + "@parcel/runtime-react-refresh": "2.9.3", + "@parcel/runtime-service-worker": "2.9.3", + "@parcel/transformer-babel": "2.9.3", + "@parcel/transformer-css": "2.9.3", + "@parcel/transformer-html": "2.9.3", + "@parcel/transformer-image": "2.9.3", + "@parcel/transformer-js": "2.9.3", + "@parcel/transformer-json": "2.9.3", + "@parcel/transformer-postcss": "2.9.3", + "@parcel/transformer-posthtml": "2.9.3", + "@parcel/transformer-raw": "2.9.3", + "@parcel/transformer-react-refresh-wrap": "2.9.3", + "@parcel/transformer-svg": "2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "@parcel/core": "^2.9.3" } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/config-default/node_modules/@parcel/runtime-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.3.tgz", + "integrity": "sha512-EvIy+qXcKnB5qxHhe96zmJpSAViNVXHfQI5RSdZ2a7CPwORwhTI+zPNT9sb7xb/WwFw/WuTTgzT40b41DceU6Q==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-slot": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/core": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.3.tgz", + "integrity": "sha512-4KlM1Zr/jpsqWuMXr2zmGsaOUs1zMMFh9vfCNKRZkptf+uk8I3sugHbNdo+F5B+4e2yMuOEb1zgAmvJLeuH6ww==", + "dependencies": { + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/cache": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/graph": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/profiler": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "abortcontroller-polyfill": "^1.1.9", + "base-x": "^3.0.8", + "browserslist": "^4.6.6", + "clone": "^2.1.1", + "dotenv": "^7.0.0", + "dotenv-expand": "^5.1.0", + "json5": "^2.2.0", + "msgpackr": "^1.5.4", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "node_modules/@parcel/core/node_modules/dotenv": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==", + "engines": { + "node": ">=6" } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/core/node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/@parcel/diagnostic": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.3.tgz", + "integrity": "sha512-6jxBdyB3D7gP4iE66ghUGntWt2v64E6EbD4AetZk+hNJpgudOOPsKTovcMi/i7I4V0qD7WXSF4tvkZUoac0jwA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "@mischnic/json-sourcemap": "^0.1.0", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" + "node_modules/@parcel/events": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.3.tgz", + "integrity": "sha512-K0Scx+Bx9f9p1vuShMzNwIgiaZUkxEnexaKYHYemJrM7pMAqxIuIqhnvwurRCsZOVLUJPDDNJ626cWTc5vIq+A==", + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-context": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/fs": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.3.tgz", + "integrity": "sha512-/PrRKgCRw22G7rNPSpgN3Q+i2nIkZWuvIOAdMG4KWXC4XLp8C9jarNaWd5QEQ75amjhQSl3oUzABzkdCtkKrgg==", "dependencies": { - "@babel/runtime": "^7.13.10" + "@parcel/fs-search": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/watcher": "^2.0.7", + "@parcel/workers": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "@parcel/core": "^2.9.3" } }, - "node_modules/@radix-ui/react-context-menu": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-menu": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-controllable-state": "1.0.0" + "node_modules/@parcel/fs-search": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.3.tgz", + "integrity": "sha512-nsNz3bsOpwS+jphcd+XjZL3F3PDq9lik0O8HPm5f6LYkqKWT+u/kgQzA8OkAHCR3q96LGiHxUywHPEBc27vI4Q==", + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/graph": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.3.tgz", + "integrity": "sha512-3LmRJmF8+OprAr6zJT3X2s8WAhLKkrhi6RsFlMWHifGU5ED1PFcJWFbOwJvSjcAhMQJP0fErcFIK1Ludv3Vm3g==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/hash": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.3.tgz", + "integrity": "sha512-qlH5B85XLzVAeijgKPjm1gQu35LoRYX/8igsjnN8vOlbc3O8BYAUIutU58fbHbtE8MJPbxQQUw7tkTjeoujcQQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "xxhash-wasm": "^0.4.2" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.0.2", - "license": "MIT", + "node_modules/@parcel/logger": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.3.tgz", + "integrity": "sha512-5FNBszcV6ilGFcijEOvoNVG6IUJGsnMiaEnGQs7Fvc1dktTjEddnoQbIYhcSZL63wEmzBZOgkT5yDMajJ/41jw==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-dismissable-layer": "1.0.2", - "@radix-ui/react-focus-guards": "1.0.0", - "@radix-ui/react-focus-scope": "1.0.1", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-portal": "1.0.1", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-slot": "1.0.1", - "@radix-ui/react-use-controllable-state": "1.0.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.5" + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-direction": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/markdown-ansi": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.3.tgz", + "integrity": "sha512-/Q4X8F2aN8UNjAJrQ5NfK2OmZf6shry9DqetUSEndQ0fHonk78WKt6LT0zSKEBEW/bB/bXk6mNMsCup6L8ibjQ==", "dependencies": { - "@babel/runtime": "^7.13.10" + "chalk": "^4.1.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.0.2", - "license": "MIT", + "node_modules/@parcel/namer-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.3.tgz", + "integrity": "sha512-1ynFEcap48/Ngzwwn318eLYpLUwijuuZoXQPCsEQ21OOIOtfhFQJaPwXTsw6kRitshKq76P2aafE0BioGSqxcA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-escape-keydown": "1.0.2" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/node-resolver-core": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.3.tgz", + "integrity": "sha512-AjxNcZVHHJoNT/A99PKIdFtwvoze8PAiC3yz8E/dRggrDIOboUEodeQYV5Aq++aK76uz/iOP0tST2T8A5rhb1A==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-menu": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-controllable-state": "1.0.0" + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-css": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.3.tgz", + "integrity": "sha512-RK1QwcSdWDNUsFvuLy0hgnYKtPQebzCb0vPPzqs6LhL+vqUu9utOyRycGaQffHCkHVQP6zGlN+KFssd7YtFGhA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "browserslist": "^4.6.6", + "lightningcss": "^1.16.1", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-data-url": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-data-url/-/optimizer-data-url-2.9.3.tgz", + "integrity": "sha512-k8lOKLzgZ24JKOuyrNe5PptoH8GJ78AwnumG1xEOKZ77gZnUgdrn3XdjzE28ZqTI4LFkT3jApUiBKBmqnWDe7Q==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "isbinaryfile": "^4.0.2", + "mime": "^2.4.4" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-htmlnano": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.3.tgz", + "integrity": "sha512-9g/KBck3c6DokmJfvJ5zpHFBiCSolaGrcsTGx8C3YPdCTVTI9P1TDCwUxvAr4LjpcIRSa82wlLCI+nF6sSgxKA==", "dependencies": { - "@babel/runtime": "^7.13.10" + "@parcel/plugin": "2.9.3", + "htmlnano": "^2.0.0", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "svgo": "^2.4.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-use-callback-ref": "1.0.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-icons": { - "version": "1.1.1", - "license": "MIT", - "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x" + "node_modules/@parcel/optimizer-htmlnano/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" } }, - "node_modules/@radix-ui/react-id": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-htmlnano/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-layout-effect": "1.0.0" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/@radix-ui/react-menu": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-htmlnano/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-collection": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-direction": "1.0.0", - "@radix-ui/react-dismissable-layer": "1.0.0", - "@radix-ui/react-focus-guards": "1.0.0", - "@radix-ui/react-focus-scope": "1.0.0", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-popper": "1.0.0", - "@radix-ui/react-portal": "1.0.0", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-roving-focus": "1.0.0", - "@radix-ui/react-slot": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.4" + "mdn-data": "2.0.14", + "source-map": "^0.6.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-htmlnano/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-escape-keydown": "1.0.0" + "css-tree": "^1.1.2" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-htmlnano/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/@parcel/optimizer-htmlnano/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0" + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-image": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.3.tgz", + "integrity": "sha512-530YzthE7kmecnNhPbkAK+26yQNt69pfJrgE0Ev0BZaM1Wu2+33nki7o8qvkTkikhPrurEJLGIXt1qKmbKvCbA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "@parcel/core": "^2.9.3" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-svgo": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.3.tgz", + "integrity": "sha512-ytQS0wY5JJhWU4mL0wfhYDUuHcfuw+Gy2+JcnTm1t1AZXHlOTbU6EzRWNqBShsgXjvdrQQXizAe3B6GFFlFJVQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "svgo": "^2.4.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@parcel/optimizer-svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/optimizer-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" + "mdn-data": "2.0.14", + "source-map": "^0.6.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/@radix-ui/react-menu/node_modules/react-remove-scroll": { - "version": "2.5.4", - "license": "MIT", + "node_modules/@parcel/optimizer-svgo/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dependencies": { - "react-remove-scroll-bar": "^2.3.3", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" + "css-tree": "^1.1.2" }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "node": ">=8.0.0" } }, - "node_modules/@radix-ui/react-menu/node_modules/tslib": { - "version": "2.4.1", - "license": "0BSD" + "node_modules/@parcel/optimizer-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" }, - "node_modules/@radix-ui/react-popover": { - "version": "1.0.2", - "license": "MIT", + "node_modules/@parcel/optimizer-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-dismissable-layer": "1.0.2", - "@radix-ui/react-focus-guards": "1.0.0", - "@radix-ui/react-focus-scope": "1.0.1", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-popper": "1.0.1", - "@radix-ui/react-portal": "1.0.1", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-slot": "1.0.1", - "@radix-ui/react-use-controllable-state": "1.0.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.5" + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/optimizer-swc": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.3.tgz", + "integrity": "sha512-GQINNeqtdpL1ombq/Cpwi6IBk02wKJ/JJbYbyfHtk8lxlq13soenpwOlzJ5T9D2fdG+FUhai9NxpN5Ss4lNoAg==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.1" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/package-manager": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.3.tgz", + "integrity": "sha512-NH6omcNTEupDmW4Lm1e4NUYBjdqkURxgZ4CNESESInHJe6tblVhNB8Rpr1ar7zDar7cly9ILr8P6N3Ei7bTEjg==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@floating-ui/react-dom": "0.7.2", - "@radix-ui/react-arrow": "1.0.1", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.0", - "@radix-ui/react-use-rect": "1.0.0", - "@radix-ui/react-use-size": "1.0.0", - "@radix-ui/rect": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/node-resolver-core": "3.0.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "@parcel/core": "^2.9.3" } }, - "node_modules/@radix-ui/react-popper": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/packager-css": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.3.tgz", + "integrity": "sha512-mePiWiYZOULY6e1RdAIJyRoYqXqGci0srOaVZYaP7mnrzvJgA63kaZFFsDiEWghunQpMUuUjM2x/vQVHzxmhKQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@floating-ui/react-dom": "0.7.2", - "@radix-ui/react-arrow": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-layout-effect": "1.0.0", - "@radix-ui/react-use-rect": "1.0.0", - "@radix-ui/react-use-size": "1.0.0", - "@radix-ui/rect": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/packager-html": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.3.tgz", + "integrity": "sha512-0Ex+O0EaZf9APNERRNGgGto02hFJ6f5RQEvRWBK55WAV1rXeU+kpjC0c0qZvnUaUtXfpWMsEBkevJCwDkUMeMg==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/packager-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.3.tgz", + "integrity": "sha512-V5xwkoE3zQ3R+WqAWhA1KGQ791FvJeW6KonOlMI1q76Djjgox68hhObqcLu66AmYNhR2R/wUpkP18hP2z8dSFw==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "globals": "^13.2.0", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/packager-raw": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.3.tgz", + "integrity": "sha512-oPQTNoYanQ2DdJyL61uPYK2py83rKOT8YVh2QWAx0zsSli6Kiy64U3+xOCYWgDVCrHw9+9NpQMuAdSiFg4cq8g==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.1" + "@parcel/plugin": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/packager-svg": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.3.tgz", + "integrity": "sha512-p/Ya6UO9DAkaCUFxfFGyeHZDp9YPAlpdnh1OChuwqSFOXFjjeXuoK4KLT+ZRalVBo2Jo8xF70oKMZw4MVvaL7Q==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-use-layout-effect": "1.0.0" + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "posthtml": "^0.16.4" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-primitive": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/plugin": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.3.tgz", + "integrity": "sha512-qN85Gqr2GMuxX1dT1mnuO9hOcvlEv1lrYrCxn7CJN2nUhbwcfG+LEvcrCzCOJ6XtIHm+ZBV9h9p7FfoPLvpw+g==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.1" + "@parcel/types": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/profiler": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.3.tgz", + "integrity": "sha512-pyHc9lw8VZDfgZoeZWZU9J0CVEv1Zw9O5+e0DJPDPHuXJYr72ZAOhbljtU3owWKAeW+++Q2AZWkbUGEOjI/e6g==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-collection": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-direction": "1.0.0", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-controllable-state": "1.0.0" + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3", + "chrome-trace-event": "^1.0.2" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/reporter-bundle-buddy": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-bundle-buddy/-/reporter-bundle-buddy-2.9.3.tgz", + "integrity": "sha512-9ftzLZ161USdvnxueT55EWufLI48va0xJfB5MAJLG92VAS1N1FSFgYKdkGFzBKw0eK9UScQNYnntCGC17rBayQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" + "@parcel/plugin": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/reporter-dev-server": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.3.tgz", + "integrity": "sha512-s6eboxdLEtRSvG52xi9IiNbcPKC0XMVmvTckieue2EqGDbDcaHQoHmmwkk0rNq0/Z/UxelGcQXoIYC/0xq3ykQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/resolver-default": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.3.tgz", + "integrity": "sha512-8ESJk1COKvDzkmOnppNXoDamNMlYVIvrKc2RuFPmp8nKVj47R6NwMgvwxEaatyPzvkmyTpq5RvG9I3HFc+r4Cw==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" + "@parcel/node-resolver-core": "3.0.3", + "@parcel/plugin": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.0.2", - "license": "MIT", + "node_modules/@parcel/runtime-browser-hmr": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.3.tgz", + "integrity": "sha512-EgiDIDrVAWpz7bOzWXqVinQkaFjLwT34wsonpXAbuI7f7r00d52vNAQC9AMu+pTijA3gyKoJ+Q4NWPMZf7ACDA==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-dismissable-layer": "1.0.2", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-popper": "1.0.1", - "@radix-ui/react-portal": "1.0.1", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-slot": "1.0.1", - "@radix-ui/react-use-controllable-state": "1.0.0", - "@radix-ui/react-visually-hidden": "1.0.1" + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/runtime-js": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", + "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.1" + "@parcel/plugin": "2.8.3", + "@parcel/utils": "2.8.3", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.8.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@parcel/runtime-js/node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", + "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@parcel/runtime-js/node_modules/@lmdb/lmdb-darwin-x64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", + "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@parcel/runtime-js/node_modules/@lmdb/lmdb-linux-arm": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", + "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@parcel/runtime-js/node_modules/@lmdb/lmdb-linux-arm64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", + "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@parcel/runtime-js/node_modules/@lmdb/lmdb-linux-x64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", + "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@parcel/runtime-js/node_modules/@lmdb/lmdb-win32-x64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", + "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/cache": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", + "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@floating-ui/react-dom": "0.7.2", - "@radix-ui/react-arrow": "1.0.1", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-primitive": "1.0.1", - "@radix-ui/react-use-layout-effect": "1.0.0", - "@radix-ui/react-use-rect": "1.0.0", - "@radix-ui/react-use-size": "1.0.0", - "@radix-ui/rect": "1.0.0" + "@parcel/fs": "2.8.3", + "@parcel/logger": "2.8.3", + "@parcel/utils": "2.8.3", + "lmdb": "2.5.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "@parcel/core": "^2.8.3" } }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/runtime-js/node_modules/@parcel/codeframe": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", + "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", "dependencies": { - "@babel/runtime": "^7.13.10" + "chalk": "^4.1.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/runtime-js/node_modules/@parcel/diagnostic": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", + "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" + "@mischnic/json-sourcemap": "^0.1.0", + "nullthrows": "^1.1.1" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" + "node_modules/@parcel/runtime-js/node_modules/@parcel/events": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", + "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "engines": { + "node": ">= 12.0.0" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@parcel/runtime-js/node_modules/@parcel/fs": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", + "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", "dependencies": { - "@babel/runtime": "^7.13.10" + "@parcel/fs-search": "2.8.3", + "@parcel/types": "2.8.3", + "@parcel/utils": "2.8.3", + "@parcel/watcher": "^2.0.7", + "@parcel/workers": "2.8.3" }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.3" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/fs-search": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", + "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/hash": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", + "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "dependencies": { + "detect-libc": "^1.0.3", + "xxhash-wasm": "^0.4.2" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/logger": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", + "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "dependencies": { + "@parcel/diagnostic": "2.8.3", + "@parcel/events": "2.8.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/markdown-ansi": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", + "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "dependencies": { + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/package-manager": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", + "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "dependencies": { + "@parcel/diagnostic": "2.8.3", + "@parcel/fs": "2.8.3", + "@parcel/logger": "2.8.3", + "@parcel/types": "2.8.3", + "@parcel/utils": "2.8.3", + "@parcel/workers": "2.8.3", + "semver": "^5.7.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.3" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/plugin": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", + "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "dependencies": { + "@parcel/types": "2.8.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/types": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", + "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "dependencies": { + "@parcel/cache": "2.8.3", + "@parcel/diagnostic": "2.8.3", + "@parcel/fs": "2.8.3", + "@parcel/package-manager": "2.8.3", + "@parcel/source-map": "^2.1.1", + "@parcel/workers": "2.8.3", + "utility-types": "^3.10.0" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/utils": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", + "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "dependencies": { + "@parcel/codeframe": "2.8.3", + "@parcel/diagnostic": "2.8.3", + "@parcel/hash": "2.8.3", + "@parcel/logger": "2.8.3", + "@parcel/markdown-ansi": "2.8.3", + "@parcel/source-map": "^2.1.1", + "chalk": "^4.1.0" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-js/node_modules/@parcel/workers": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", + "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "dependencies": { + "@parcel/diagnostic": "2.8.3", + "@parcel/logger": "2.8.3", + "@parcel/types": "2.8.3", + "@parcel/utils": "2.8.3", + "chrome-trace-event": "^1.0.2", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.8.3" + } + }, + "node_modules/@parcel/runtime-js/node_modules/lmdb": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", + "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "hasInstallScript": true, + "dependencies": { + "msgpackr": "^1.5.4", + "node-addon-api": "^4.3.0", + "node-gyp-build-optional-packages": "5.0.3", + "ordered-binary": "^1.2.4", + "weak-lru-cache": "^1.2.2" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "2.5.2", + "@lmdb/lmdb-darwin-x64": "2.5.2", + "@lmdb/lmdb-linux-arm": "2.5.2", + "@lmdb/lmdb-linux-arm64": "2.5.2", + "@lmdb/lmdb-linux-x64": "2.5.2", + "@lmdb/lmdb-win32-x64": "2.5.2" + } + }, + "node_modules/@parcel/runtime-js/node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "node_modules/@parcel/runtime-js/node_modules/node-gyp-build-optional-packages": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", + "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/@parcel/runtime-js/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@parcel/runtime-react-refresh": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.3.tgz", + "integrity": "sha512-XBgryZQIyCmi6JwEfMUCmINB3l1TpTp9a2iFxmYNpzHlqj4Ve0saKaqWOVRLvC945ZovWIBzcSW2IYqWKGtbAA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "react-error-overlay": "6.0.9", + "react-refresh": "^0.9.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/runtime-react-refresh/node_modules/react-refresh": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", + "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@parcel/runtime-service-worker": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.3.tgz", + "integrity": "sha512-qLJLqv1mMdWL7gyh8aKBFFAuEiJkhUUgLKpdn6eSfH/R7kTtb76WnOwqUrhvEI9bZFUM/8Pa1bzJnPpqSOM+Sw==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/source-map": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz", + "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": "^12.18.3 || >=14" + } + }, + "node_modules/@parcel/transformer-babel": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.3.tgz", + "integrity": "sha512-pURtEsnsp3h6tOBDuzh9wRvVtw4PgIlqwAArIWdrG7iwqOUYv9D8ME4+ePWEu7MQWAp58hv9pTJtqWv4T+Sq8A==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "browserslist": "^4.6.6", + "json5": "^2.2.0", + "nullthrows": "^1.1.1", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-css": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.3.tgz", + "integrity": "sha512-duWMdbEBBPjg3fQdXF16iWIdThetDZvCs2TpUD7xOlXH6kR0V5BJy8ONFT15u1RCqIV9hSNGaS3v3I9YRNY5zQ==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "browserslist": "^4.6.6", + "lightningcss": "^1.16.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-graphql": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-graphql/-/transformer-graphql-2.9.3.tgz", + "integrity": "sha512-cIohsH3WlXgn63baU35ZoWHzttmkyE2Q1pexKjszODzSUq3pdcg+9k4rB/z8GGMzXvFRYuBgl2M2Ukqz7SueMg==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "graphql": "^15.0.0", + "graphql-import-macro": "^1.0.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-html": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.3.tgz", + "integrity": "sha512-0NU4omcHzFXA1seqftAXA2KNZaMByoKaNdXnLgBgtCGDiYvOcL+6xGHgY6pw9LvOh5um10KI5TxSIMILoI7VtA==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2", + "srcset": "4" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-image": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.3.tgz", + "integrity": "sha512-7CEe35RaPadQzLIuxzTtIxnItvOoy46hcbXtOdDt6lmVa4omuOygZYRIya2lsGIP4JHvAaALMb5nt99a1uTwJg==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/transformer-inline-string": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-inline-string/-/transformer-inline-string-2.9.3.tgz", + "integrity": "sha512-IZNd0Ksl32psX1M41KbUc4BmvVSoLVnlpaMrh9C/l+piFSkDXWMnF0PONX/RcxYMBIwB2jYllheIKH54naeNaA==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-js": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.3.tgz", + "integrity": "sha512-Z2MVVg5FYcPOfxlUwxqb5l9yjTMEqE3KI3zq2MBRUme6AV07KxLmCDF23b6glzZlHWQUE8MXzYCTAkOPCcPz+Q==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/utils": "2.9.3", + "@parcel/workers": "2.9.3", + "@swc/helpers": "^0.5.0", + "browserslist": "^4.6.6", + "nullthrows": "^1.1.1", + "regenerator-runtime": "^0.13.7", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@parcel/transformer-js/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/@parcel/transformer-json": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.3.tgz", + "integrity": "sha512-yNL27dbOLhkkrjaQjiQ7Im9VOxmkfuuSNSmS0rA3gEjVcm07SLKRzWkAaPnyx44Lb6bzyOTWwVrb9aMmxgADpA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "json5": "^2.2.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-less": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-less/-/transformer-less-2.9.3.tgz", + "integrity": "sha512-qwF5NQ8rPZjS79tv9RRPxzkZcwLcI4Xg2gHm9c1PvsgoaL2tVNpfjiRA6MOrzfJp+xr7xEzeMDZksOJ1WQiiQg==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "less": "^4.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-postcss": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.3.tgz", + "integrity": "sha512-HoDvPqKzhpmvMmHqQhDnt8F1vH61m6plpGiYaYnYv2Om4HHi5ZIq9bO+9QLBnTKfaZ7ndYSefTKOxTYElg7wyw==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "clone": "^2.1.1", + "nullthrows": "^1.1.1", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-posthtml": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.3.tgz", + "integrity": "sha512-2fQGgrzRmaqbWf3y2/T6xhqrNjzqMMKksqJzvc8TMfK6f2kg3Ddjv158eaSW2JdkV39aY7tvAOn5f1uzo74BMA==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-raw": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.3.tgz", + "integrity": "sha512-oqdPzMC9QzWRbY9J6TZEqltknjno+dY24QWqf8ondmdF2+W+/2mRDu59hhCzQrqUHgTq4FewowRZmSfpzHxwaQ==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-react-refresh-wrap": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.3.tgz", + "integrity": "sha512-cb9NyU6oJlDblFIlzqIE8AkvRQVGl2IwJNKwD4PdE7Y6sq2okGEPG4hOw3k/Y9JVjM4/2pUORqvjSRhWwd9oVQ==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "react-refresh": "^0.9.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-react-refresh-wrap/node_modules/react-refresh": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.9.0.tgz", + "integrity": "sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@parcel/transformer-sass": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-sass/-/transformer-sass-2.9.3.tgz", + "integrity": "sha512-i9abj9bKg3xCHghJyTM3rUVxIEn9n1Rl+DFdpyNAD8VZ52COfOshFDQOWNuhU1hEnJOFYCjnfcO0HRTsg3dWmg==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "^2.1.1", + "sass": "^1.38.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-svg": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.3.tgz", + "integrity": "sha512-ypmE+dzB09IMCdEAkOsSxq1dEIm2A3h67nAFz4qbfHbwNgXBUuy/jB3ZMwXN/cO0f7SBh/Ap8Jhq6vmGqB5tWw==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "nullthrows": "^1.1.1", + "posthtml": "^0.16.5", + "posthtml-parser": "^0.10.1", + "posthtml-render": "^3.0.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-svg-react": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg-react/-/transformer-svg-react-2.9.3.tgz", + "integrity": "sha512-RXmCn58CkCBhpsS1AaRBrSRla0U5JN3r3hb7kQvEb+d7chGnsxCCWsBxtlrxPUjoUFLdQli9rhpCTkiyOBXY2A==", + "dependencies": { + "@parcel/plugin": "2.9.3", + "@svgr/core": "^6.2.0", + "@svgr/plugin-jsx": "^6.2.0", + "@svgr/plugin-svgo": "^6.2.0" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/transformer-worklet": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/transformer-worklet/-/transformer-worklet-2.9.3.tgz", + "integrity": "sha512-Fgd81OTOvAxAKoBGsQow/mgxELaNG1FeZW4DuDEPo/hR3lbs90oYuVpG2thdx7hmi/W6xqhrLaEN5Ea1v0LvEA==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/types": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.3.tgz", + "integrity": "sha512-NSNY8sYtRhvF1SqhnIGgGvJocyWt1K8Tnw5cVepm0g38ywtX6mwkBvMkmeehXkII4mSUn+frD9wGsydTunezvA==", + "dependencies": { + "@parcel/cache": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/source-map": "^2.1.1", + "@parcel/workers": "2.9.3", + "utility-types": "^3.10.0" + } + }, + "node_modules/@parcel/utils": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.3.tgz", + "integrity": "sha512-cesanjtj/oLehW8Waq9JFPmAImhoiHX03ihc3JTWkrvJYSbD7wYKCDgPAM3JiRAqvh1LZ6P699uITrYWNoRLUg==", + "dependencies": { + "@parcel/codeframe": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/markdown-ansi": "2.9.3", + "@parcel/source-map": "^2.1.1", + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.2.0.tgz", + "integrity": "sha512-71S4TF+IMyAn24PK4KSkdKtqJDR3zRzb0HE3yXpacItqTM7XfF2f5q9NEGLEVl0dAaBAGfNwDCjH120y25F6Tg==", + "hasInstallScript": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.2.0", + "@parcel/watcher-darwin-arm64": "2.2.0", + "@parcel/watcher-darwin-x64": "2.2.0", + "@parcel/watcher-linux-arm-glibc": "2.2.0", + "@parcel/watcher-linux-arm64-glibc": "2.2.0", + "@parcel/watcher-linux-arm64-musl": "2.2.0", + "@parcel/watcher-linux-x64-glibc": "2.2.0", + "@parcel/watcher-linux-x64-musl": "2.2.0", + "@parcel/watcher-win32-arm64": "2.2.0", + "@parcel/watcher-win32-x64": "2.2.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.2.0.tgz", + "integrity": "sha512-nU2wh00CTQT9rr1TIKTjdQ9lAGYpmz6XuKw0nAwAN+S2A5YiD55BK1u+E5WMCT8YOIDe/n6gaj4o/Bi9294SSQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.2.0.tgz", + "integrity": "sha512-cJl0UZDcodciy3TDMomoK/Huxpjlkkim3SyMgWzjovHGOZKNce9guLz2dzuFwfObBFCjfznbFMIvAZ5syXotYw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.2.0.tgz", + "integrity": "sha512-QI77zxaGrCV1StKcoRYfsUfmUmvPMPfQrubkBBy5XujV2fwaLgZivQOTQMBgp5K2+E19u1ufpspKXAPqSzpbyg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.2.0.tgz", + "integrity": "sha512-I2GPBcAXazPzabCmfsa3HRRW+MGlqxYd8g8RIueJU+a4o5nyNZDz0CR1cu0INT0QSQXEZV7w6UE8Hz9CF8u3Pg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.2.0.tgz", + "integrity": "sha512-St5mlfp+2lS9AmgixUqfwJa/DwVmTCJxC1HcOubUTz6YFOKIlkHCeUa1Bxi4E/tR/HSez8+heXHL8HQkJ4Bd8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.2.0.tgz", + "integrity": "sha512-jS+qfhhoOBVWwMLP65MaG8xdInMK30pPW8wqTCg2AAuVJh5xepMbzkhHJ4zURqHiyY3EiIRuYu4ONJKCxt8iqA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.2.0.tgz", + "integrity": "sha512-xJvJ7R2wJdi47WZBFS691RDOWvP1j/IAs3EXaWVhDI8FFITbWrWaln7KoNcR0Y3T+ZwimFY/cfb0PNht1q895g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.2.0.tgz", + "integrity": "sha512-D+NMpgr23a+RI5mu8ZPKWy7AqjBOkURFDgP5iIXXEf/K3hm0jJ3ogzi0Ed2237B/CdYREimCgXyeiAlE/FtwyA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.2.0.tgz", + "integrity": "sha512-z225cPn3aygJsyVUOWwfyW+fY0Tvk7N3XCOl66qUPFxpbuXeZuiuuJemmtm8vxyqa3Ur7peU/qJxrpC64aeI7Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.2.0.tgz", + "integrity": "sha512-JqGW0RJ61BkKx+yYzIURt9s53P7xMVbv0uxYPzAXLBINGaFmkIKSuUPyBVfy8TMbvp93lvF4SPBNDzVRJfvgOw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/workers": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.3.tgz", + "integrity": "sha512-zRrDuZJzTevrrwElYosFztgldhqW6G9q5zOeQXfVQFkkEJCNfg36ixeiofKRU8uu2x+j+T6216mhMNB6HiuY+w==", + "dependencies": { + "@parcel/diagnostic": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/profiler": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "peerDependencies": { + "@parcel/core": "^2.9.3" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@plasmohq/consolidate": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@plasmohq/consolidate/-/consolidate-0.17.0.tgz", + "integrity": "sha512-Na8imBnvzYPtzkK+9Uv9hPZ/oJti/0jgiQWD222SHxHw2QCVuR4KzslxXCy/rS8gGluSiTs1BGVvc3d2O6aJCA==", + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "peerDependencies": { + "arc-templates": "^0.5.3", + "atpl": ">=0.7.6", + "babel-core": "^6.26.3", + "bracket-template": "^1.1.5", + "coffeescript": "^2.7.0", + "dot": "^1.1.3", + "eco": "^1.1.0-rc-3", + "ect": "^0.5.9", + "ejs": "^3.1.5", + "haml-coffee": "^1.14.1", + "hamlet": "^0.3.3", + "hamljs": "^0.6.2", + "handlebars": "^4.7.6", + "hogan.js": "^3.0.2", + "htmling": "^0.0.8", + "jazz": "^0.0.18", + "jqtpl": "~1.1.0", + "just": "^0.1.8", + "liquid": "^5.1.1", + "liquor": "^0.0.5", + "lodash": "^4.17.20", + "marko": "^3.14.4", + "mote": "^0.2.0", + "mustache": "^4.0.1", + "nunjucks": "^3.2.2", + "plates": "~0.4.11", + "pug": "^3.0.0", + "qejs": "^3.0.5", + "ractive": "^1.3.12", + "razor-tmpl": "^1.3.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "slm": "^2.0.0", + "squirrelly": "^5.1.0", + "teacup": "^2.0.0", + "templayed": ">=0.2.3", + "then-pug": "*", + "tinyliquid": "^0.2.34", + "toffee": "^0.3.6", + "twig": "^1.15.2", + "twing": "^5.0.2", + "underscore": "^1.11.0", + "vash": "^0.13.0", + "velocityjs": "^2.0.1", + "walrus": "^0.10.1", + "whiskers": "^0.4.0" + }, + "peerDependenciesMeta": { + "arc-templates": { + "optional": true + }, + "atpl": { + "optional": true + }, + "babel-core": { + "optional": true + }, + "bracket-template": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "dot": { + "optional": true + }, + "eco": { + "optional": true + }, + "ect": { + "optional": true + }, + "ejs": { + "optional": true + }, + "haml-coffee": { + "optional": true + }, + "hamlet": { + "optional": true + }, + "hamljs": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "hogan.js": { + "optional": true + }, + "htmling": { + "optional": true + }, + "jazz": { + "optional": true + }, + "jqtpl": { + "optional": true + }, + "just": { + "optional": true + }, + "liquid": { + "optional": true + }, + "liquor": { + "optional": true + }, + "lodash": { + "optional": true + }, + "marko": { + "optional": true + }, + "mote": { + "optional": true + }, + "mustache": { + "optional": true + }, + "nunjucks": { + "optional": true + }, + "plates": { + "optional": true + }, + "pug": { + "optional": true + }, + "qejs": { + "optional": true + }, + "ractive": { + "optional": true + }, + "razor-tmpl": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "slm": { + "optional": true + }, + "squirrelly": { + "optional": true + }, + "teacup": { + "optional": true + }, + "templayed": { + "optional": true + }, + "then-pug": { + "optional": true + }, + "tinyliquid": { + "optional": true + }, + "toffee": { + "optional": true + }, + "twig": { + "optional": true + }, + "twing": { + "optional": true + }, + "underscore": { + "optional": true + }, + "vash": { + "optional": true + }, + "velocityjs": { + "optional": true + }, + "walrus": { + "optional": true + }, + "whiskers": { + "optional": true + } + } + }, + "node_modules/@plasmohq/init": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@plasmohq/init/-/init-0.7.0.tgz", + "integrity": "sha512-P75g48dqOGneJ+n0AcqnLE/TYflcaPc3B7h6EopnCBBYUDnCNBMwYmKAkaf5pnhsEB0ybPS6TU1C2DTGfqaW7A==" + }, + "node_modules/@plasmohq/parcel-bundler": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-bundler/-/parcel-bundler-0.5.5.tgz", + "integrity": "sha512-QCMmmfic514CfdXMJ7JMWUnqDzIHKVKyYeqPpUDsXON6JvA1yTmO5mEQSls8+5u/HpocP9QmTskQOHu3RCNX9A==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/graph": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "1.1.1" + }, + "engines": { + "node": ">= 16.0.0", + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-compressor-utf8": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-compressor-utf8/-/parcel-compressor-utf8-0.0.6.tgz", + "integrity": "sha512-dtbZXi2gAHyVhxqxF2SvJtwDOy02QYRjwCJYOFsQR79qwAiuUBaeQ47p++vFrqNX86mo1lUtZniJl63xNQi08w==", + "dependencies": { + "@parcel/plugin": "2.9.3" + }, + "engines": { + "parcel": ">= 2.8.0" + } + }, + "node_modules/@plasmohq/parcel-config": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-config/-/parcel-config-0.40.0.tgz", + "integrity": "sha512-aDyZIL3ScTmA1CsB/Sym7SxOMVSFUgNQrFovD+sl1M2nrYytqkLDFs7mspCpBlsxCGt97s8rD/kufke21UUHRA==", + "dependencies": { + "@parcel/compressor-raw": "2.9.3", + "@parcel/config-default": "2.9.3", + "@parcel/core": "2.9.3", + "@parcel/optimizer-data-url": "2.9.3", + "@parcel/reporter-bundle-buddy": "2.9.3", + "@parcel/resolver-default": "2.9.3", + "@parcel/runtime-js": "2.8.3", + "@parcel/runtime-service-worker": "2.9.3", + "@parcel/source-map": "2.1.1", + "@parcel/transformer-babel": "2.9.3", + "@parcel/transformer-css": "2.9.3", + "@parcel/transformer-graphql": "2.9.3", + "@parcel/transformer-inline-string": "2.9.3", + "@parcel/transformer-js": "2.9.3", + "@parcel/transformer-less": "2.9.3", + "@parcel/transformer-postcss": "2.9.3", + "@parcel/transformer-raw": "2.9.3", + "@parcel/transformer-react-refresh-wrap": "2.9.3", + "@parcel/transformer-sass": "2.9.3", + "@parcel/transformer-svg-react": "2.9.3", + "@parcel/transformer-worklet": "2.9.3", + "@plasmohq/parcel-bundler": "0.5.5", + "@plasmohq/parcel-compressor-utf8": "0.0.6", + "@plasmohq/parcel-namer-manifest": "0.3.12", + "@plasmohq/parcel-optimizer-encapsulate": "0.0.7", + "@plasmohq/parcel-optimizer-es": "0.4.0", + "@plasmohq/parcel-packager": "0.6.14", + "@plasmohq/parcel-resolver": "0.13.1", + "@plasmohq/parcel-resolver-post": "0.4.2", + "@plasmohq/parcel-runtime": "0.23.0", + "@plasmohq/parcel-transformer-inject-env": "0.2.11", + "@plasmohq/parcel-transformer-inline-css": "0.3.9", + "@plasmohq/parcel-transformer-manifest": "0.17.8", + "@plasmohq/parcel-transformer-svelte": "0.5.2", + "@plasmohq/parcel-transformer-vue": "0.5.0" + } + }, + "node_modules/@plasmohq/parcel-core": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-core/-/parcel-core-0.1.8.tgz", + "integrity": "sha512-kMWuazvf925ZAn2yHzzrb4Zsje1titFmvi/C5cXrI0TH58eT7n6GUiRXiOYP4JgGDHs/pEygx3WPuyWVTNF2HQ==", + "dependencies": { + "@parcel/cache": "2.9.3", + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/events": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/graph": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/logger": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "2.1.1", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@parcel/watcher": "2.2.0", + "@parcel/workers": "2.9.3", + "abortcontroller-polyfill": "1.7.5", + "nullthrows": "1.1.1" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-namer-manifest": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-namer-manifest/-/parcel-namer-manifest-0.3.12.tgz", + "integrity": "sha512-mNyIVK4nRbjlnXXUygBcmV7xLzgS1HZ3vedxUrMQah0Wp0Y20GFcomToDBC0w9NXIZVSSKY0bRIeh0B6/verfQ==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-optimizer-encapsulate": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-optimizer-encapsulate/-/parcel-optimizer-encapsulate-0.0.7.tgz", + "integrity": "sha512-mA9kY5dwuebQ4vLX6A5yTFo0gZZNWKUHpF6yO0lYq3oP843MyRJS8SxAtzQb4vTlVWPk3SX6Yw81DgBo4I6Xiw==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "2.1.1", + "@parcel/types": "2.9.3" + }, + "engines": { + "parcel": ">= 2.8.0" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-optimizer-es/-/parcel-optimizer-es-0.4.0.tgz", + "integrity": "sha512-Iz1cTuw38wEbSQ36/dVKh5MyRA12/Ecrx90pqaIkoqA9ZSZuxuWWa7rPa3bVMFkzi28BpVHW1z9EnhVN4188kQ==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "2.1.1", + "@parcel/utils": "2.9.3", + "@swc/core": "1.3.82", + "nullthrows": "1.1.1" + }, + "engines": { + "parcel": ">= 2.8.0" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.82.tgz", + "integrity": "sha512-jpC1a18HMH67018Ij2jh+hT7JBFu7ZKcQVfrZ8K6JuEY+kjXmbea07P9MbQUZbAe0FB+xi3CqEVCP73MebodJQ==", + "hasInstallScript": true, + "dependencies": { + "@swc/types": "^0.1.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.82", + "@swc/core-darwin-x64": "1.3.82", + "@swc/core-linux-arm-gnueabihf": "1.3.82", + "@swc/core-linux-arm64-gnu": "1.3.82", + "@swc/core-linux-arm64-musl": "1.3.82", + "@swc/core-linux-x64-gnu": "1.3.82", + "@swc/core-linux-x64-musl": "1.3.82", + "@swc/core-win32-arm64-msvc": "1.3.82", + "@swc/core-win32-ia32-msvc": "1.3.82", + "@swc/core-win32-x64-msvc": "1.3.82" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-darwin-arm64": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.82.tgz", + "integrity": "sha512-JfsyDW34gVKD3uE0OUpUqYvAD3yseEaicnFP6pB292THtLJb0IKBBnK50vV/RzEJtc1bR3g1kNfxo2PeurZTrA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-darwin-x64": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.82.tgz", + "integrity": "sha512-ogQWgNMq7qTpITjcP3dnzkFNj7bh6SwMr859GvtOTrE75H7L7jDWxESfH4f8foB/LGxBKiDNmxKhitCuAsZK4A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.82.tgz", + "integrity": "sha512-7TMXG1lXlNhD0kUiEqs+YlGV4irAdBa2quuy+XI3oJf2fBK6dQfEq4xBy65B3khrorzQS3O0oDGQ+cmdpHExHA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.82.tgz", + "integrity": "sha512-26JkOujbzcItPAmIbD5vHJxQVy5ihcSu3YHTKwope1h28sApZdtE7S3e2G3gsZRTIdsCQkXUtAQeqHxGWWR3pw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.82.tgz", + "integrity": "sha512-8Izj9tuuMpoc3cqiPBRtwqpO1BZ/+sfZVsEhLxrbOFlcSb8LnKyMle1g3JMMUwI4EU75RGVIzZMn8A6GOKdJbA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.82.tgz", + "integrity": "sha512-0GSrIBScQwTaPv46T2qB7XnDYxndRCpwH4HMjh6FN+I+lfPUhTSJKW8AonqrqT1TbpFIgvzQs7EnTsD7AnSCow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.82.tgz", + "integrity": "sha512-KJUnaaepDKNzrEbwz4jv0iC3/t9x0NSoe06fnkAlhh2+NFKWKKJhVCOBTrpds8n7eylBDIXUlK34XQafjVMUdg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.82.tgz", + "integrity": "sha512-TR3MHKhDYIyGyFcyl2d/p1ftceXcubAhX5wRSOdtOyr5+K/v3jbyCCqN7bbqO5o43wQVCwwR/drHleYyDZvg8Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.82.tgz", + "integrity": "sha512-ZX4HzVVt6hs84YUg70UvyBJnBOIspmQQM0iXSzBvOikk3zRoN7BnDwQH4GScvevCEBuou60+i4I6d5kHLOfh8Q==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-optimizer-es/node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.82", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.82.tgz", + "integrity": "sha512-4mJMnex21kbQoaHeAmHnVwQN9/XAfPszJ6n9HI7SVH+aAHnbBIR0M59/b50/CJMjTj5niUGk7EwQ3nhVNOG32g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@plasmohq/parcel-packager": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-packager/-/parcel-packager-0.6.14.tgz", + "integrity": "sha512-pFab9COfafx66CtOFWgLgKf4TUPLb5EiTO4ecRz1HDINSvPl48ci+3czmtSzOI4+b1uiqZYxUB3eeaMfh9XWpA==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "nullthrows": "1.1.1" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-resolver": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-resolver/-/parcel-resolver-0.13.1.tgz", + "integrity": "sha512-IuKr3Ue1+2fsyJPQuHh4Yh36L3FI/2I27X6hC+NHlX/1j9fVYiFk89dTSPNhvAdGN/hwsMjQ/jCiKZGW1157xg==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "fast-glob": "3.2.12", + "fs-extra": "11.1.1", + "got": "13.0.0" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-resolver-post": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-resolver-post/-/parcel-resolver-post-0.4.2.tgz", + "integrity": "sha512-dbrwjUQEhKqKBEgVJjL5ls1p6bpQ3VlDXI5REoaSpwoPcB7TRAcUfTwV4oNGE4eTnw4ElF08JkyslYvKgxosAw==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/hash": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "tsup": "7.2.0", + "typescript": "5.2.2" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-resolver-post/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@plasmohq/parcel-resolver/node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@plasmohq/parcel-resolver/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@plasmohq/parcel-resolver/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@plasmohq/parcel-resolver/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@plasmohq/parcel-runtime": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-runtime/-/parcel-runtime-0.23.0.tgz", + "integrity": "sha512-+ZqH9XksSbWPC6pnvjmvmykxh1SfyYkSKyOeNQSeHsPFo40fADUKOda8Hw/vm/g5p8GIlv5YSb2iYZzCWmKs1g==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "react-refresh": "0.14.0" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-inject-env": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-transformer-inject-env/-/parcel-transformer-inject-env-0.2.11.tgz", + "integrity": "sha512-eGwwoaDbPPwrRcEgOi/BpLVGe5ttrBhs91NBcKMpE/D5gktfbJPD1zHG8MPtQdE4Iq23aG3JUbiT5clmdwtUhQ==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-transformer-inline-css/-/parcel-transformer-inline-css-0.3.9.tgz", + "integrity": "sha512-da1gVe3TX7J5lC6M04iHzp2NPwhh40n/Gx/Di9o2KLLEYe0q+pKlI5OjN9zf5kpXwXfVO7QzE5B1/tRGoEu2Bw==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/utils": "2.9.3", + "browserslist": "4.21.10", + "lightningcss": "1.21.7" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.7.tgz", + "integrity": "sha512-xITZyh5sLFwRPYUSw15T00Rm7gcQ1qOPuQwNOcvHsTm6nLWTQ723w7zl42wrC5t+xtdg6FPmnXHml1nZxxvp1w==", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.21.7", + "lightningcss-darwin-x64": "1.21.7", + "lightningcss-freebsd-x64": "1.21.7", + "lightningcss-linux-arm-gnueabihf": "1.21.7", + "lightningcss-linux-arm64-gnu": "1.21.7", + "lightningcss-linux-arm64-musl": "1.21.7", + "lightningcss-linux-x64-gnu": "1.21.7", + "lightningcss-linux-x64-musl": "1.21.7", + "lightningcss-win32-x64-msvc": "1.21.7" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-darwin-arm64": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.7.tgz", + "integrity": "sha512-tt7hIsFio9jZofTVHtCACz6rB6c9RyABMXfA9A/VcKOjS3sq+koX/QkRJWY06utwOImbJIXBC5hbg9t3RkPUAQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-darwin-x64": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.7.tgz", + "integrity": "sha512-F4gS4bf7eWekfPT+TxJNm/pF+QRgZiTrTkQH6cw4/UWfdeZISfuhD5El2dm16giFnY0K5ylIwO+ZusgYNkGSXA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-freebsd-x64": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.21.7.tgz", + "integrity": "sha512-RMfNzJWXCSfPnL55fcLWEAadcY6QUFT0S8NceNKYzp1KiCZtkJIy6RQ5SaVxPzRqd3iMsahUf5sfnG8N1UQSNQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.7.tgz", + "integrity": "sha512-biSRUDZNx7vubWP1jArw/qqfZKPGpkV/qzunasZzxmqijbZ43sW9faDQYxWNcxPWljJJdF/qs6qcurYFovWtrQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.7.tgz", + "integrity": "sha512-PENY8QekqL9TG3AY/A7rkUBb5ymefGxea7Oe7+x7Hbw4Bz4Hpj5cec5OoMypMqFbURPmpi0fTWx4vSWUPzpDcA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.7.tgz", + "integrity": "sha512-pfOipKvA/0X1OjRaZt3870vnV9UGBSjayIqHh0fGx/+aRz3O0MVFHE/60P2UWXpM3YGJEw/hMWtNkrFwqOge8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.7.tgz", + "integrity": "sha512-dgcsis4TAA7s0ia4f31QHX+G4PWPwxk+wJaEQLaV0NdJs09O5hHoA8DpLEr8nrvc/tsRTyVNBP1rDtgzySjpXg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-linux-x64-musl": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.7.tgz", + "integrity": "sha512-A+9dXpxld3p4Cd6fxev2eqEvaauYtrgNpXV3t7ioCJy30Oj9nYiNGwiGusM+4MJVcEpUPGUGiuAqY4sWilRDwA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-inline-css/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.7.tgz", + "integrity": "sha512-07/8vogEq+C/mF99pdMhh/f19/xreq8N9Ca6AWeVHZIdODyF/pt6KdKSCWDZWIn+3CUxI8gCJWuUWyOc3xymvw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@plasmohq/parcel-transformer-manifest": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-transformer-manifest/-/parcel-transformer-manifest-0.17.8.tgz", + "integrity": "sha512-G6XISWddf900Q/4ABlFLBJcqvN1VTYF06NytTOMSDO4dOraxGhgZ0CyC990b+LJEa7nc5xf4xhHQxf3mkjALPQ==", + "dependencies": { + "@mischnic/json-sourcemap": "0.1.0", + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "content-security-policy-parser": "0.4.1", + "json-schema-to-ts": "2.9.2", + "nullthrows": "1.1.1" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-manifest/node_modules/@lezer/common": { + "version": "0.15.12", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", + "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==" + }, + "node_modules/@plasmohq/parcel-transformer-manifest/node_modules/@lezer/lr": { + "version": "0.15.8", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", + "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "dependencies": { + "@lezer/common": "^0.15.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-manifest/node_modules/@mischnic/json-sourcemap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz", + "integrity": "sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==", + "dependencies": { + "@lezer/common": "^0.15.7", + "@lezer/lr": "^0.15.4", + "json5": "^2.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-svelte": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-transformer-svelte/-/parcel-transformer-svelte-0.5.2.tgz", + "integrity": "sha512-kZevkKYgYB7KZqi1+8k5ELqrSNKakqBwuTLnIT0BOx/8VKTJ6fwkzW0SR1OFsDJIACRFbMLO77u+erwHkodBEA==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "2.1.1", + "@parcel/utils": "2.9.3", + "svelte": "4.0.1" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@plasmohq/parcel-transformer-vue": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@plasmohq/parcel-transformer-vue/-/parcel-transformer-vue-0.5.0.tgz", + "integrity": "sha512-/3oVbajt+DRqtbM0RkKFtfyZR8DVjcsYpj1jHqPParGVBiXwgP0D/8Bj5p5/5Iqihs08gzasTcjKcwQKKdj0og==", + "dependencies": { + "@parcel/core": "2.9.3", + "@parcel/diagnostic": "2.9.3", + "@parcel/plugin": "2.9.3", + "@parcel/source-map": "2.1.1", + "@parcel/types": "2.9.3", + "@parcel/utils": "2.9.3", + "@plasmohq/consolidate": "0.17.0", + "@vue/compiler-sfc": "3.3.4", + "nullthrows": "1.1.1", + "semver": "7.5.4", + "vue": "3.3.4" + }, + "engines": { + "parcel": ">= 2.7.0" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.21", + "dev": true, + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dialog": "1.0.2", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-menu": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-context-menu/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-escape-keydown": "1.0.2" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-menu": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-icons": { + "version": "1.1.1", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x" + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.0", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.0.0", + "@radix-ui/react-portal": "1.0.0", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-roving-focus": "1.0.0", + "@radix-ui/react-slot": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.4" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-escape-keydown": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-menu/node_modules/react-remove-scroll": { + "version": "2.5.4", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/tslib": { + "version": "2.4.1", + "license": "0BSD" + }, + "node_modules/@radix-ui/react-popover": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-focus-guards": "1.0.0", + "@radix-ui/react-focus-scope": "1.0.1", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.0.1", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-arrow": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "0.7.2", + "@radix-ui/react-arrow": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-rect": "1.0.0", + "@radix-ui/react-use-size": "1.0.0", + "@radix-ui/rect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "0.7.2", + "@radix-ui/react-arrow": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-rect": "1.0.0", + "@radix-ui/react-use-size": "1.0.0", + "@radix-ui/rect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-collection": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-direction": "1.0.0", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-primitive": "1.0.0", + "@radix-ui/react-use-callback-ref": "1.0.0", + "@radix-ui/react-use-controllable-state": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.0", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-dismissable-layer": "1.0.2", + "@radix-ui/react-id": "1.0.0", + "@radix-ui/react-popper": "1.0.1", + "@radix-ui/react-portal": "1.0.1", + "@radix-ui/react-presence": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-slot": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.0", + "@radix-ui/react-visually-hidden": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "0.7.2", + "@radix-ui/react-arrow": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.0", + "@radix-ui/react-context": "1.0.0", + "@radix-ui/react-primitive": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.0", + "@radix-ui/react-use-rect": "1.0.0", + "@radix-ui/react-use-size": "1.0.0", + "@radix-ui/rect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/rect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.0" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.1" + }, + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@react-dnd/asap": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", + "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==" + }, + "node_modules/@react-dnd/invariant": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + }, + "node_modules/@react-hook/latest": { + "version": "1.0.3", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@react-hook/throttle": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "@react-hook/latest": "^1.0.2" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/@rushstack/node-core-library": { + "version": "3.59.7", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "~1.2.1", + "fs-extra": "~7.0.1", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "z-schema": "~5.0.2" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "4.15.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "colors": "~1.2.1", + "string-argv": "~0.3.1" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@stitches/react": { + "version": "1.2.8", + "license": "MIT", + "peerDependencies": { + "react": ">= 16.3.0" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.5.1.tgz", + "integrity": "sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-6.5.1.tgz", + "integrity": "sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-6.5.1.tgz", + "integrity": "sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-6.5.1.tgz", + "integrity": "sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/rect": "1.0.0" + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-6.5.1.tgz", + "integrity": "sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-layout-effect": "1.0.0" + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-6.5.1.tgz", + "integrity": "sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.0.1", - "license": "MIT", + "node_modules/@svgr/babel-preset": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-6.5.1.tgz", + "integrity": "sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==", "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.1" + "@svgr/babel-plugin-add-jsx-attribute": "^6.5.1", + "@svgr/babel-plugin-remove-jsx-attribute": "*", + "@svgr/babel-plugin-remove-jsx-empty-expression": "*", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^6.5.1", + "@svgr/babel-plugin-svg-dynamic-title": "^6.5.1", + "@svgr/babel-plugin-svg-em-dimensions": "^6.5.1", + "@svgr/babel-plugin-transform-react-native-svg": "^6.5.1", + "@svgr/babel-plugin-transform-svg-component": "^6.5.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@radix-ui/rect": { - "version": "1.0.0", - "license": "MIT", + "node_modules/@svgr/core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-6.5.1.tgz", + "integrity": "sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==", "dependencies": { - "@babel/runtime": "^7.13.10" + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/plugin-jsx": "^6.5.1", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@react-hook/latest": { - "version": "1.0.3", - "license": "MIT", + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-6.5.1.tgz", + "integrity": "sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==", + "dependencies": { + "@babel/types": "^7.20.0", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-6.5.1.tgz", + "integrity": "sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==", + "dependencies": { + "@babel/core": "^7.19.6", + "@svgr/babel-preset": "^6.5.1", + "@svgr/hast-util-to-babel-ast": "^6.5.1", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, "peerDependencies": { - "react": ">=16.8" + "@svgr/core": "^6.0.0" } }, - "node_modules/@react-hook/throttle": { - "version": "2.2.0", - "license": "MIT", + "node_modules/@svgr/plugin-svgo": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-6.5.1.tgz", + "integrity": "sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==", "dependencies": { - "@react-hook/latest": "^1.0.2" + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "svgo": "^2.8.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" }, "peerDependencies": { - "react": ">=16.8" + "@svgr/core": "*" } }, - "node_modules/@rushstack/node-core-library": { - "version": "3.59.7", - "dev": true, - "license": "MIT", + "node_modules/@svgr/plugin-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dependencies": { - "colors": "~1.2.1", - "fs-extra": "~7.0.1", - "import-lazy": "~4.0.0", - "jju": "~1.4.0", - "resolve": "~1.22.1", - "semver": "~7.5.4", - "z-schema": "~5.0.2" + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@svgr/plugin-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/@svgr/plugin-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@swc/core": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.104.tgz", + "integrity": "sha512-9LWH/qzR/Pmyco+XwPiPfz59T1sryI7o5dmqb593MfCkaX5Fzl9KhwQTI47i21/bXYuCdfa9ySZuVkzXMirYxA==", + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.3.104", + "@swc/core-darwin-x64": "1.3.104", + "@swc/core-linux-arm-gnueabihf": "1.3.104", + "@swc/core-linux-arm64-gnu": "1.3.104", + "@swc/core-linux-arm64-musl": "1.3.104", + "@swc/core-linux-x64-gnu": "1.3.104", + "@swc/core-linux-x64-musl": "1.3.104", + "@swc/core-win32-arm64-msvc": "1.3.104", + "@swc/core-win32-ia32-msvc": "1.3.104", + "@swc/core-win32-x64-msvc": "1.3.104" }, "peerDependencies": { - "@types/node": "*" + "@swc/helpers": "^0.5.0" }, "peerDependenciesMeta": { - "@types/node": { + "@swc/helpers": { "optional": true } } }, - "node_modules/@rushstack/rig-package": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "~1.22.1", - "strip-json-comments": "~3.1.1" + "node_modules/@swc/core-darwin-arm64": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.104.tgz", + "integrity": "sha512-rCnVj8x3kn6s914Adddu+zROHUn6mUEMkNKUckofs3W9OthNlZXJA3C5bS2MMTRFXCWamJ0Zmh6INFpz+f4Tfg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" } }, - "node_modules/@rushstack/ts-command-line": { - "version": "4.15.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "colors": "~1.2.1", - "string-argv": "~0.3.1" + "node_modules/@swc/core-darwin-x64": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.104.tgz", + "integrity": "sha512-LBCWGTYkn1UjyxrmcLS3vZgtCDVhwxsQMV7jz5duc7Gas8SRWh6ZYqvUkjlXMDX1yx0uvzHrkaRw445+zDRj7Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.104.tgz", + "integrity": "sha512-iFbsWcx0TKHWnFBNCuUstYqRtfkyBx7FKv5To1Hx14EMuvvoCD/qUoJEiNfDQN5n/xU9g5xq4RdbjEWCFLhAbA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.104.tgz", + "integrity": "sha512-1BIIp+nUPrRHHaJ35YJqrwXPwYSITp5robqqjyTwoKGw2kq0x+A964kpWul6v0d7A9Ial8fyH4m13eSWBodD2A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.104.tgz", + "integrity": "sha512-IyDNkzpKwvLqmRwTW+s8f8OsOSSj1N6juZKbvNHpZRfWZkz3T70q3vJlDBWQwy8z8cm7ckd7YUT3eKcSBPPowg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.104.tgz", + "integrity": "sha512-MfX/wiRdTjE5uXHTDnaX69xI4UBfxIhcxbVlMj//N+7AX/G2pl2UFityfVMU2HpM12BRckrCxVI8F/Zy3DZkYQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.104.tgz", + "integrity": "sha512-5yeILaxA31gGEmquErO8yxlq1xu0XVt+fz5mbbKXKZMRRILxYxNzAGb5mzV41r0oHz6Vhv4AXX/WMCmeWl+HkQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.104.tgz", + "integrity": "sha512-rwcImsYnWDWGmeESG0XdGGOql5s3cG5wA8C4hHHKdH76zamPfDKKQFBsjmoNi0f1IsxaI9AJPeOmD4bAhT1ZoQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.104.tgz", + "integrity": "sha512-ICDA+CJLYC7NkePnrbh/MvXwDQfy3rZSFgrVdrqRosv9DKHdFjYDnA9++7ozjrIdFdBrFW2NR7pyUcidlwhNzA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@stitches/react": { - "version": "1.2.8", - "license": "MIT", - "peerDependencies": { - "react": ">= 16.3.0" + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.3.104", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.104.tgz", + "integrity": "sha512-fZJ1Ju62U4lMZVU+nHxLkFNcu0hG5Y0Yj/5zjrlbuX5N8J5eDndWAFsVnQhxRTZqKhZB53pvWRQs5FItSDqgXg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" } }, + "node_modules/@swc/counter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", + "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==" + }, "node_modules/@swc/helpers": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", @@ -3408,6 +7041,22 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==" + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/@tldraw/core": { "version": "1.21.0", "license": "MIT", @@ -3475,24 +7124,32 @@ "node": ">= 10" } }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.8", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.9", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/argparse": { @@ -3537,6 +7194,16 @@ "@types/chai": "*" } }, + "node_modules/@types/chrome": { + "version": "0.0.251", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.251.tgz", + "integrity": "sha512-UF+yr0LEKWWGsKxQ5A3XOSF5SNoU1ctW3pXcWJPpT8OOUTEspYeaLU8spDKe+6xalXeMTS0TBrX1g0b6qlWmkw==", + "dev": true, + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, "node_modules/@types/color-hash": { "version": "1.0.2", "dev": true, @@ -3579,7 +7246,6 @@ }, "node_modules/@types/estree": { "version": "1.0.1", - "dev": true, "license": "MIT" }, "node_modules/@types/express": { @@ -3603,10 +7269,31 @@ "@types/range-parser": "*" } }, + "node_modules/@types/filesystem": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.35.tgz", + "integrity": "sha512-1eKvCaIBdrD2mmMgy5dwh564rVvfEhZTWVQQGRNn0Nt4ZEnJ0C8oSUCzvMKRA4lGde5oEVo+q2MrTTbV/GHDCQ==", + "dev": true, + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.32.tgz", + "integrity": "sha512-Kpi2GXQyYJdjL8mFclL1eDgihn1SIzorMZjD94kdPZh9E4VxGOeyjPxi5LpsM4Zku7P0reqegZTt2GxhmA9VBg==", + "dev": true + }, "node_modules/@types/google-protobuf": { "version": "3.15.5", "license": "MIT" }, + "node_modules/@types/har-format": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.15.tgz", + "integrity": "sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==", + "dev": true + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.1", "license": "MIT", @@ -3615,6 +7302,11 @@ "hoist-non-react-statics": "^3.3.0" } }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==" + }, "node_modules/@types/http-proxy": { "version": "1.17.7", "dev": true, @@ -3642,7 +7334,6 @@ }, "node_modules/@types/json-schema": { "version": "7.0.9", - "dev": true, "license": "MIT" }, "node_modules/@types/lodash": { @@ -3673,9 +7364,19 @@ }, "node_modules/@types/node": { "version": "20.4.2", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prismjs": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==" + }, "node_modules/@types/prompts": { "version": "2.4.5", "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.5.tgz", @@ -3714,8 +7415,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.2.21", - "license": "MIT", + "version": "18.2.37", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.37.tgz", + "integrity": "sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3723,9 +7425,10 @@ } }, "node_modules/@types/react-dom": { - "version": "18.2.7", + "version": "18.2.15", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz", + "integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "*" } @@ -4326,114 +8029,138 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz", + "integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.45", + "@babel/parser": "^7.21.3", + "@vue/shared": "3.3.4", "estree-walker": "^2.0.2", - "source-map": "^0.6.1" + "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz", + "integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==", "dependencies": { - "@vue/compiler-core": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.2.45", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.45", - "@vue/compiler-dom": "3.2.45", - "@vue/compiler-ssr": "3.2.45", - "@vue/reactivity-transform": "3.2.45", - "@vue/shared": "3.2.45", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz", + "integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-ssr": "3.3.4", + "@vue/reactivity-transform": "3.3.4", + "@vue/shared": "3.3.4", "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", + "magic-string": "^0.30.0", "postcss": "^8.1.10", - "source-map": "^0.6.1" + "source-map-js": "^1.0.2" } }, + "node_modules/@vue/compiler-sfc/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.25.9", - "license": "MIT", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz", + "integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==", "dependencies": { - "@vue/compiler-dom": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-dom": "3.3.4", + "@vue/shared": "3.3.4" } }, "node_modules/@vue/reactivity": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", + "integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==", "dependencies": { - "@vue/shared": "3.2.45" + "@vue/shared": "3.3.4" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz", + "integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.45", - "@vue/shared": "3.2.45", + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4", "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" + "magic-string": "^0.30.0" } }, + "node_modules/@vue/reactivity-transform/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, "node_modules/@vue/reactivity-transform/node_modules/magic-string": { - "version": "0.25.9", - "license": "MIT", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" } }, "node_modules/@vue/runtime-core": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz", + "integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==", "dependencies": { - "@vue/reactivity": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/reactivity": "3.3.4", + "@vue/shared": "3.3.4" } }, "node_modules/@vue/runtime-dom": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz", + "integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==", "dependencies": { - "@vue/runtime-core": "3.2.45", - "@vue/shared": "3.2.45", - "csstype": "^2.6.8" + "@vue/runtime-core": "3.3.4", + "@vue/shared": "3.3.4", + "csstype": "^3.1.1" } }, - "node_modules/@vue/runtime-dom/node_modules/csstype": { - "version": "2.6.21", - "license": "MIT" - }, "node_modules/@vue/server-renderer": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz", + "integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==", "dependencies": { - "@vue/compiler-ssr": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-ssr": "3.3.4", + "@vue/shared": "3.3.4" }, "peerDependencies": { - "vue": "3.2.45" + "vue": "3.3.4" } }, "node_modules/@vue/shared": { - "version": "3.2.45", - "license": "MIT" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", + "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", @@ -4622,6 +8349,11 @@ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", "dev": true }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + }, "node_modules/accepts": { "version": "1.3.8", "dev": true, @@ -4636,7 +8368,6 @@ }, "node_modules/acorn": { "version": "8.10.0", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -4663,7 +8394,7 @@ }, "node_modules/acorn-walk": { "version": "8.2.0", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -4752,6 +8483,31 @@ "ajv": "^6.9.1" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-html-community": { "version": "0.0.8", "dev": true, @@ -4765,7 +8521,6 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4773,7 +8528,6 @@ }, "node_modules/ansi-styles": { "version": "3.2.1", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -4782,9 +8536,13 @@ "node": ">=4" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, "node_modules/anymatch": { "version": "3.1.2", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -4796,7 +8554,7 @@ }, "node_modules/arg": { "version": "4.1.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/argparse": { @@ -4830,6 +8588,14 @@ "version": "2.4.1", "license": "0BSD" }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/array-flatten": { "version": "2.1.2", "dev": true, @@ -4837,7 +8603,6 @@ }, "node_modules/array-union": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4903,6 +8668,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" + }, "node_modules/babel-code-frame": { "version": "6.26.0", "dev": true, @@ -5094,12 +8872,18 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "dev": true, "license": "MIT" }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/base64-js": { "version": "1.5.1", - "dev": true, "funding": [ { "type": "github", @@ -5132,12 +8916,62 @@ }, "node_modules/binary-extensions": { "version": "2.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, "node_modules/bn.js": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", @@ -5212,6 +9046,11 @@ "multicast-dns-service-types": "^1.1.0" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "dev": true, @@ -5223,7 +9062,6 @@ }, "node_modules/braces": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -5347,7 +9185,6 @@ }, "node_modules/browserslist": { "version": "4.21.10", - "dev": true, "funding": [ { "type": "opencollective", @@ -5378,7 +9215,6 @@ }, "node_modules/buffer": { "version": "6.0.3", - "dev": true, "funding": [ { "type": "github", @@ -5401,7 +9237,7 @@ }, "node_modules/buffer-from": { "version": "1.1.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/buffer-indexof": { @@ -5440,11 +9276,35 @@ "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, "node_modules/call-bind": { "version": "1.0.2", "license": "MIT", @@ -5458,12 +9318,22 @@ }, "node_modules/callsites": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001524", "funding": [ @@ -5502,7 +9372,6 @@ }, "node_modules/chalk": { "version": "4.1.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5517,7 +9386,6 @@ }, "node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5531,7 +9399,6 @@ }, "node_modules/chalk/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -5542,12 +9409,10 @@ }, "node_modules/chalk/node_modules/color-name": { "version": "1.1.4", - "dev": true, "license": "MIT" }, "node_modules/chalk/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5555,7 +9420,6 @@ }, "node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5564,6 +9428,16 @@ "node": ">=8" } }, + "node_modules/change-case": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.1.2.tgz", + "integrity": "sha512-CAtbGEDulyjzs05RXy3uKcwqeztz/dMEuAc1Xu9NQBsbrhuGMneL0u9Dj5SoutLKBFYun8txxYIwhjtLNfUmCA==" + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -5578,7 +9452,6 @@ }, "node_modules/chokidar": { "version": "3.5.3", - "dev": true, "funding": [ { "type": "individual", @@ -5602,9 +9475,13 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "node_modules/chrome-trace-event": { "version": "1.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0" @@ -5631,6 +9508,36 @@ "node": ">=6" } }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "engines": { + "node": ">= 12" + } + }, "node_modules/client-only": { "version": "0.0.1", "license": "MIT" @@ -5665,11 +9572,36 @@ "node": ">=6" } }, - "node_modules/clsx": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=6" + "node_modules/clsx": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/code-red/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/code-red/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" } }, "node_modules/codemirror": { @@ -5685,9 +9617,20 @@ "@codemirror/view": "^6.0.0" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", - "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -5699,9 +9642,33 @@ }, "node_modules/color-name": { "version": "1.1.3", - "dev": true, "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/colorette": { "version": "2.0.16", "dev": true, @@ -5729,7 +9696,7 @@ }, "node_modules/commander": { "version": "2.20.3", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/comment-parser": { @@ -5794,6 +9761,15 @@ "dev": true, "license": "MIT" }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", "dev": true, @@ -5841,6 +9817,14 @@ ], "license": "MIT" }, + "node_modules/content-security-policy-parser": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/content-security-policy-parser/-/content-security-policy-parser-0.4.1.tgz", + "integrity": "sha512-NNJS8XPnx3OKr/CUOSwDSJw+lWTrZMYnclLKj0Y9CYOfJNJTWLFGPg3u2hYgbXMXKVRkZR2fbyReNQ1mUff/Qg==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/content-type": { "version": "1.0.4", "dev": true, @@ -5851,7 +9835,6 @@ }, "node_modules/convert-source-map": { "version": "1.8.0", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.1.1" @@ -5862,6 +9845,17 @@ "dev": true, "license": "MIT" }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", "dev": true, @@ -5936,6 +9930,21 @@ "dev": true, "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/create-ecdh": { "version": "4.0.4", "dev": true, @@ -5977,7 +9986,7 @@ }, "node_modules/create-require": { "version": "1.1.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/create-yorkie-app": { @@ -5990,7 +9999,6 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6022,6 +10030,117 @@ "node": "*" } }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "optional": true, + "peer": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "optional": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "optional": true, + "peer": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "optional": true, + "peer": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", @@ -6030,6 +10149,42 @@ "optional": true, "peer": true }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "optional": true, + "peer": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "optional": true, + "peer": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "optional": true, + "peer": true + }, "node_modules/cssstyle": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", @@ -6062,7 +10217,6 @@ }, "node_modules/debug": { "version": "4.3.3", - "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -6082,6 +10236,31 @@ "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -6109,11 +10288,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.3", "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "dev": true, @@ -6125,6 +10320,33 @@ "node": ">= 10" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "dev": true, @@ -6181,6 +10403,14 @@ "node": ">= 0.6" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/des.js": { "version": "1.0.1", "dev": true, @@ -6210,6 +10440,17 @@ "node": ">=0.10.0" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/detect-node": { "version": "2.1.0", "dev": true, @@ -6245,7 +10486,6 @@ }, "node_modules/dir-glob": { "version": "3.0.1", - "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -6254,6 +10494,24 @@ "node": ">=8" } }, + "node_modules/dnd-core": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-14.0.1.tgz", + "integrity": "sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A==", + "dependencies": { + "@react-dnd/asap": "^4.0.0", + "@react-dnd/invariant": "^2.0.0", + "redux": "^4.1.1" + } + }, + "node_modules/dnd-core/node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/dns-equal": { "version": "1.0.0", "dev": true, @@ -6287,6 +10545,27 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domain-browser": { "version": "4.22.0", "dev": true, @@ -6298,6 +10577,17 @@ "url": "https://bevry.me/fund" } }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -6310,11 +10600,62 @@ "node": ">=12" } }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "engines": { + "node": ">=12" + } + }, "node_modules/duplexer": { "version": "0.1.2", "dev": true, "license": "MIT" }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "node_modules/ee-first": { "version": "1.1.1", "dev": true, @@ -6322,7 +10663,6 @@ }, "node_modules/electron-to-chromium": { "version": "1.4.504", - "dev": true, "license": "ISC" }, "node_modules/elliptic": { @@ -6346,7 +10686,6 @@ }, "node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "license": "MIT" }, "node_modules/encodeurl": { @@ -6357,6 +10696,14 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.15.0", "dev": true, @@ -6373,7 +10720,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, "engines": { "node": ">=0.12" }, @@ -6392,6 +10738,26 @@ "node": ">=4" } }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-abstract": { "version": "1.19.1", "dev": true, @@ -6810,7 +11176,6 @@ }, "node_modules/escalade": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7166,7 +11531,6 @@ }, "node_modules/events": { "version": "3.3.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.x" @@ -7183,7 +11547,6 @@ }, "node_modules/execa": { "version": "5.1.1", - "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -7203,6 +11566,14 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/express": { "version": "4.18.2", "dev": true, @@ -7342,19 +11713,36 @@ "version": "3.0.2", "license": "MIT" }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "dev": true, "license": "MIT" }, "node_modules/fast-diff": { "version": "1.2.0", "license": "Apache-2.0" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" + }, "node_modules/fast-glob": { - "version": "3.2.11", - "dev": true, - "license": "MIT", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -7383,7 +11771,6 @@ }, "node_modules/fastq": { "version": "1.13.0", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -7400,6 +11787,37 @@ "node": ">=0.8.0" } }, + "node_modules/fflate": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.1.tgz", + "integrity": "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==" + }, + "node_modules/figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "dependencies": { + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "dev": true, @@ -7413,7 +11831,6 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -7471,6 +11888,32 @@ "dev": true, "license": "MIT" }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -7485,6 +11928,14 @@ "node": ">= 6" } }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "engines": { + "node": ">= 14.17" + } + }, "node_modules/forwarded": { "version": "0.2.0", "dev": true, @@ -7501,6 +11952,11 @@ "node": ">= 0.6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fs-extra": { "version": "7.0.1", "dev": true, @@ -7526,7 +11982,6 @@ }, "node_modules/fsevents": { "version": "2.3.2", - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7547,7 +12002,6 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -7589,9 +12043,19 @@ "node": ">=6" } }, + "node_modules/get-port": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.0.0.tgz", + "integrity": "sha512-mDHFgApoQd+azgMdwylJrv2DX47ywGq1i5VFJE7fZ0dttNq3iQMfsU4IvEgBHojA3KqEudyu7Vq+oN8kNaNkWw==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "6.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -7626,6 +12090,11 @@ "url": "https://github.com/wojtekmaj/get-user-locale?sponsor=1" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob": { "version": "7.2.0", "dev": true, @@ -7647,7 +12116,6 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -7662,7 +12130,6 @@ }, "node_modules/globals": { "version": "13.16.0", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.20.2" @@ -7676,7 +12143,6 @@ }, "node_modules/globby": { "version": "11.1.0", - "dev": true, "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -7703,10 +12169,50 @@ "version": "3.19.4", "license": "BSD-3-Clause" }, + "node_modules/got": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz", + "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "license": "ISC" }, + "node_modules/graphql": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz", + "integrity": "sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/graphql-import-macro": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/graphql-import-macro/-/graphql-import-macro-1.0.0.tgz", + "integrity": "sha512-YK4g6iP60H++MpP93tb0VwOg7aM5iIC0hdSQKTrEDANeLWf0KFAT9dwlBeMDrhY+jcW7qsAEDtaw58cgVnQXAw==", + "dependencies": { + "graphql": "^15.0.0" + } + }, "node_modules/grpc-web": { "version": "1.3.1", "license": "Apache-2.0" @@ -7799,7 +12305,6 @@ }, "node_modules/has-flag": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -7936,6 +12441,141 @@ "dev": true, "license": "MIT" }, + "node_modules/htmlnano": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.0.tgz", + "integrity": "sha512-jVGRE0Ep9byMBKEu0Vxgl8dhXYOUk0iNQ2pjsG+BcRB0u0oDF5A9p/iBGMg/PGKYUyMD0OAGu8dVT5Lzj8S58g==", + "dependencies": { + "cosmiconfig": "^8.0.0", + "posthtml": "^0.16.5", + "timsort": "^0.3.0" + }, + "peerDependencies": { + "cssnano": "^6.0.0", + "postcss": "^8.3.11", + "purgecss": "^5.0.0", + "relateurl": "^0.2.7", + "srcset": "4.0.0", + "svgo": "^3.0.2", + "terser": "^5.10.0", + "uncss": "^0.17.3" + }, + "peerDependenciesMeta": { + "cssnano": { + "optional": true + }, + "postcss": { + "optional": true + }, + "purgecss": { + "optional": true + }, + "relateurl": { + "optional": true + }, + "srcset": { + "optional": true + }, + "svgo": { + "optional": true + }, + "terser": { + "optional": true + }, + "uncss": { + "optional": true + } + } + }, + "node_modules/htmlnano/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/htmlnano/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/htmlnano/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/htmlnano/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/htmlparser2": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", + "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.2", + "domutils": "^2.8.0", + "entities": "^3.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, "node_modules/http-deceiver": { "version": "1.2.7", "dev": true, @@ -8030,6 +12670,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/https-browserify": { "version": "1.0.0", "dev": true, @@ -8050,7 +12702,6 @@ }, "node_modules/human-signals": { "version": "2.1.0", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -8072,7 +12723,6 @@ }, "node_modules/iconv-lite": { "version": "0.4.24", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -8090,7 +12740,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "dev": true, "funding": [ { "type": "github", @@ -8108,16 +12757,32 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.2.0", - "dev": true, - "license": "MIT", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "engines": { "node": ">= 4" } }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" + }, "node_modules/import-fresh": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -8239,14 +12904,91 @@ }, "node_modules/inherits": { "version": "2.0.4", - "dev": true, "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", - "dev": true, "license": "ISC" }, + "node_modules/inquirer": { + "version": "9.2.12", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz", + "integrity": "sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==", + "dependencies": { + "@ljharb/through": "^2.3.11", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^5.0.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/internal-slot": { "version": "1.0.3", "dev": true, @@ -8316,6 +13058,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, "node_modules/is-bigint": { "version": "1.0.4", "dev": true, @@ -8329,7 +13076,6 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -8404,7 +13150,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -8423,7 +13168,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8445,7 +13189,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -8454,6 +13197,19 @@ "node": ">=0.10.0" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-json": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", + "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==" + }, "node_modules/is-nan": { "version": "1.3.2", "dev": true, @@ -8482,7 +13238,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -8535,6 +13290,14 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/is-regex": { "version": "1.1.4", "license": "MIT", @@ -8559,7 +13322,6 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8614,6 +13376,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-weakref": { "version": "1.0.1", "dev": true, @@ -8625,6 +13398,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, "node_modules/is-wsl": { "version": "2.2.0", "dev": true, @@ -8636,9 +13414,19 @@ "node": ">=8" } }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -8744,6 +13532,23 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "dev": true, @@ -8784,6 +13589,14 @@ "dev": true, "license": "MIT" }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "engines": { + "node": ">=10" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "license": "MIT" @@ -8852,7 +13665,6 @@ }, "node_modules/jsesc": { "version": "2.5.2", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -8861,11 +13673,28 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "dev": true, "license": "MIT" }, + "node_modules/json-schema-to-ts": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-2.9.2.tgz", + "integrity": "sha512-h9WqLkTVpBbiaPb5OmeUpz/FBLS/kvIJw4oRCPiEisIu2WjMh+aai0QIY2LoOhRFx5r92taGLcerIrzxKBAP6g==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@types/json-schema": "^7.0.9", + "ts-algebra": "^1.2.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -8878,7 +13707,6 @@ }, "node_modules/json5": { "version": "2.2.3", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -8901,6 +13729,14 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "dev": true, @@ -8924,6 +13760,70 @@ "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", "dev": true }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/levn": { "version": "0.4.1", "dev": true, @@ -8933,7 +13833,262 @@ "type-check": "~0.4.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.23.0.tgz", + "integrity": "sha512-SEArWKMHhqn/0QzOtclIwH5pXIYQOUEkF8DgICd/105O+GCgd7jxjNod/QPnBCSWvpRHQBGVz5fQ9uScby03zA==", + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.23.0", + "lightningcss-darwin-x64": "1.23.0", + "lightningcss-freebsd-x64": "1.23.0", + "lightningcss-linux-arm-gnueabihf": "1.23.0", + "lightningcss-linux-arm64-gnu": "1.23.0", + "lightningcss-linux-arm64-musl": "1.23.0", + "lightningcss-linux-x64-gnu": "1.23.0", + "lightningcss-linux-x64-musl": "1.23.0", + "lightningcss-win32-x64-msvc": "1.23.0" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.23.0.tgz", + "integrity": "sha512-kl4Pk3Q2lnE6AJ7Qaij47KNEfY2/UXRZBT/zqGA24B8qwkgllr/j7rclKOf1axcslNXvvUdztjo4Xqh39Yq1aA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.23.0.tgz", + "integrity": "sha512-KeRFCNoYfDdcolcFXvokVw+PXCapd2yHS1Diko1z1BhRz/nQuD5XyZmxjWdhmhN/zj5sH8YvWsp0/lPLVzqKpg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.23.0.tgz", + "integrity": "sha512-xhnhf0bWPuZxcqknvMDRFFo2TInrmQRWZGB0f6YoAsZX8Y+epfjHeeOIGCfAmgF0DgZxHwYc8mIR5tQU9/+ROA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.23.0.tgz", + "integrity": "sha512-fBamf/bULvmWft9uuX+bZske236pUZEoUlaHNBjnueaCTJ/xd8eXgb0cEc7S5o0Nn6kxlauMBnqJpF70Bgq3zg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.23.0.tgz", + "integrity": "sha512-RS7sY77yVLOmZD6xW2uEHByYHhQi5JYWmgVumYY85BfNoVI3DupXSlzbw+b45A9NnVKq45+oXkiN6ouMMtTwfg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.23.0.tgz", + "integrity": "sha512-cU00LGb6GUXCwof6ACgSMKo3q7XYbsyTj0WsKHLi1nw7pV0NCq8nFTn6ZRBYLoKiV8t+jWl0Hv8KkgymmK5L5g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.23.0.tgz", + "integrity": "sha512-q4jdx5+5NfB0/qMbXbOmuC6oo7caPnFghJbIAV90cXZqgV8Am3miZhC4p+sQVdacqxfd+3nrle4C8icR3p1AYw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.23.0.tgz", + "integrity": "sha512-G9Ri3qpmF4qef2CV/80dADHKXRAQeQXpQTLx7AiQrBYQHqBjB75oxqj06FCIe5g4hNCqLPnM9fsO4CyiT1sFSQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.23.0.tgz", + "integrity": "sha512-1rcBDJLU+obPPJM6qR5fgBUiCdZwZLafZM5f9kwjFLkb/UBNIzmae39uCSmh71nzPCTXZqHbvwu23OWnWEz+eg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "engines": { + "node": ">=14" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lmdb": { + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", + "hasInstallScript": true, + "dependencies": { + "msgpackr": "1.8.5", + "node-addon-api": "^4.3.0", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11" + } + }, + "node_modules/lmdb/node_modules/msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.1" + } + }, + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/loader-runner": { @@ -8991,6 +14146,11 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + }, "node_modules/lodash": { "version": "4.17.21", "license": "MIT" @@ -9017,6 +14177,37 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/long": { "version": "5.2.0", "license": "Apache-2.0" @@ -9040,9 +14231,19 @@ "get-func-name": "^2.0.0" } }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lru-cache": { "version": "6.0.0", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -9079,7 +14280,7 @@ }, "node_modules/make-error": { "version": "1.3.6", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/md5.js": { @@ -9092,6 +14293,11 @@ "safe-buffer": "^5.1.2" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, "node_modules/media-typer": { "version": "0.3.0", "dev": true, @@ -9111,6 +14317,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "dev": true, @@ -9118,12 +14329,10 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -9138,12 +14347,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "dev": true, - "license": "MIT", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -9166,6 +14375,17 @@ "dev": true, "license": "MIT" }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/mime-db": { "version": "1.52.0", "dev": true, @@ -9187,12 +14407,22 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "dev": true, @@ -9218,11 +14448,18 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "0.5.5", "dev": true, @@ -9234,6 +14471,11 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/mlly": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", @@ -9246,6 +14488,11 @@ "ufo": "^1.3.0" } }, + "node_modules/mnemonic-id": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/mnemonic-id/-/mnemonic-id-3.2.7.tgz", + "integrity": "sha512-kysx9gAGbvrzuFYxKkcRjnsg/NK61ovJOV4F1cHTRl9T5leg+bo6WI0pWIvOFh1Z/yDL0cjA5R3EEGPPLDv/XA==" + }, "node_modules/mrmime": { "version": "1.0.1", "dev": true, @@ -9256,9 +14503,48 @@ }, "node_modules/ms": { "version": "2.1.2", - "dev": true, "license": "MIT" }, + "node_modules/msgpackr": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.10.1.tgz", + "integrity": "sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ==", + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.0.7" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + } + }, + "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/multicast-dns": { "version": "6.2.3", "dev": true, @@ -9276,11 +14562,62 @@ "dev": true, "license": "MIT" }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "node_modules/natural-compare": { "version": "1.4.0", "dev": true, "license": "MIT" }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/negotiator": { "version": "0.6.3", "dev": true, @@ -9343,6 +14680,22 @@ "resolved": "examples/nextjs-scheduler", "link": true }, + "node_modules/node-abi": { + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", + "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.0.0.tgz", + "integrity": "sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==" + }, "node_modules/node-forge": { "version": "1.3.0", "dev": true, @@ -9351,6 +14704,25 @@ "node": ">= 6.13.0" } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-object-hash/-/node-object-hash-3.0.0.tgz", + "integrity": "sha512-jLF6tlyletktvSAawuPmH1SReP0YfZQ+tBrDiTCK+Ai7eXPMS9odi5xW/iKC7ZhrWJJ0Z5xYcW/x+1fVMn1Qvw==", + "engines": { + "node": ">=16", + "pnpm": ">=8" + } + }, "node_modules/node-polyfill-webpack-plugin": { "version": "1.1.4", "dev": true, @@ -9430,20 +14802,28 @@ }, "node_modules/node-releases": { "version": "2.0.13", - "dev": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-run-path": { "version": "4.0.1", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -9452,6 +14832,22 @@ "node": ">=8" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" + }, "node_modules/nwsapi": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", @@ -9526,7 +14922,6 @@ }, "node_modules/once": { "version": "1.4.0", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -9534,7 +14929,6 @@ }, "node_modules/onetime": { "version": "5.1.2", - "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -9586,11 +14980,65 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ordered-binary": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", + "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==" + }, "node_modules/os-browserify": { "version": "0.3.0", "dev": true, "license": "MIT" }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "engines": { + "node": ">=12.20" + } + }, "node_modules/p-map": { "version": "4.0.0", "dev": true, @@ -9625,6 +15073,47 @@ "node": ">=6" } }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, "node_modules/pako": { "version": "1.0.11", "dev": true, @@ -9636,7 +15125,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -9657,6 +15145,31 @@ "safe-buffer": "^5.1.1" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parse5": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", @@ -9700,7 +15213,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9711,9 +15223,31 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-type": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9752,14 +15286,32 @@ "version": "1.2.0", "license": "MIT" }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/periscopic/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.0", - "dev": true, - "license": "MIT", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -9767,6 +15319,23 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -9778,6 +15347,80 @@ "pathe": "^1.1.0" } }, + "node_modules/plasmo": { + "version": "0.84.0", + "resolved": "https://registry.npmjs.org/plasmo/-/plasmo-0.84.0.tgz", + "integrity": "sha512-SK6A/uX5mo4EsYiF7JySTOCp2aMo3ejfpbNey89M0zat9p0yDTKEClvMs9MWKXld5Ae0CXPaMYcZPAMvCMngPQ==", + "dependencies": { + "@expo/spawn-async": "1.7.2", + "@parcel/core": "2.9.3", + "@parcel/fs": "2.9.3", + "@parcel/package-manager": "2.9.3", + "@parcel/watcher": "2.2.0", + "@plasmohq/init": "0.7.0", + "@plasmohq/parcel-config": "0.40.0", + "@plasmohq/parcel-core": "0.1.8", + "buffer": "6.0.3", + "chalk": "5.3.0", + "change-case": "5.1.2", + "dotenv": "16.3.1", + "dotenv-expand": "10.0.0", + "events": "3.3.0", + "fast-glob": "3.3.2", + "fflate": "0.8.1", + "get-port": "7.0.0", + "got": "13.0.0", + "ignore": "5.2.4", + "inquirer": "9.2.12", + "is-path-inside": "4.0.0", + "json5": "2.2.3", + "mnemonic-id": "3.2.7", + "node-object-hash": "3.0.0", + "package-json": "8.1.1", + "process": "0.11.10", + "semver": "7.5.4", + "sharp": "0.32.6", + "tempy": "3.1.0", + "typescript": "5.2.2" + }, + "bin": { + "plasmo": "bin/index.mjs" + } + }, + "node_modules/plasmo/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/plasmo/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/plasmo/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/platform": { "version": "1.3.6", "dev": true, @@ -9831,6 +15474,53 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/postcss/node_modules/nanoid": { "version": "3.3.6", "funding": [ @@ -9847,6 +15537,123 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/posthtml": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", + "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", + "dependencies": { + "posthtml-parser": "^0.11.0", + "posthtml-render": "^3.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/posthtml-parser": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", + "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", + "dependencies": { + "htmlparser2": "^7.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/posthtml-render": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", + "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", + "dependencies": { + "is-json": "^2.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/posthtml/node_modules/posthtml-parser": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", + "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", + "dependencies": { + "htmlparser2": "^7.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "dev": true, @@ -9912,9 +15719,20 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/prism-react-renderer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.3.1.tgz", + "integrity": "sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/process": { "version": "0.11.10", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6.0" @@ -9951,6 +15769,11 @@ "react-is": "^16.13.1" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "dev": true, @@ -9971,6 +15794,12 @@ "node": ">= 0.10" } }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "optional": true + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -9995,11 +15824,19 @@ "dev": true, "license": "MIT" }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, "engines": { "node": ">=6" } @@ -10040,7 +15877,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "dev": true, "funding": [ { "type": "github", @@ -10057,6 +15893,22 @@ ], "license": "MIT" }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/quill": { "version": "1.3.7", "license": "BSD-3-Clause", @@ -10136,6 +15988,28 @@ "node": ">= 0.8" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.2.0", "license": "MIT", @@ -10146,6 +16020,22 @@ "node": ">=0.10.0" } }, + "node_modules/react-arborist": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/react-arborist/-/react-arborist-3.4.0.tgz", + "integrity": "sha512-QI46oRGXJr0oaQfqqVobIiIoqPp5Y5gM69D2A2P7uHVif+X75XWnScR5drC7YDKgJ4CXVaDeFwnYKOWRRfncMg==", + "dependencies": { + "react-dnd": "^14.0.3", + "react-dnd-html5-backend": "^14.0.3", + "react-window": "^1.8.10", + "redux": "^5.0.0", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": ">= 16.14", + "react-dom": ">= 16.14" + } + }, "node_modules/react-calendar": { "version": "4.6.0", "license": "MIT", @@ -10170,6 +16060,43 @@ } } }, + "node_modules/react-dnd": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-14.0.5.tgz", + "integrity": "sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A==", + "dependencies": { + "@react-dnd/invariant": "^2.0.0", + "@react-dnd/shallowequal": "^2.0.0", + "dnd-core": "14.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz", + "integrity": "sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw==", + "dependencies": { + "dnd-core": "14.0.1" + } + }, "node_modules/react-dom": { "version": "18.2.0", "license": "MIT", @@ -10195,6 +16122,11 @@ "react": ">=16.13.1" } }, + "node_modules/react-error-overlay": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", + "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" + }, "node_modules/react-hotkeys-hook": { "version": "3.4.7", "license": "MIT", @@ -10241,7 +16173,6 @@ }, "node_modules/react-refresh": { "version": "0.14.0", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10331,6 +16262,22 @@ "resolved": "examples/react-todomvc", "link": true }, + "node_modules/react-window": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.10.tgz", + "integrity": "sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg==", + "dependencies": { + "@babel/runtime": "^7.0.0", + "memoize-one": ">=3.1.1 <6" + }, + "engines": { + "node": ">8.0.0" + }, + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "dev": true, @@ -10352,7 +16299,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -10371,6 +16317,11 @@ "node": ">= 0.10" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, "node_modules/regenerator-runtime": { "version": "0.11.1", "dev": true, @@ -10401,6 +16352,31 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/repeating": { "version": "2.0.1", "dev": true, @@ -10449,6 +16425,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, "node_modules/resolve-cwd": { "version": "3.0.0", "dev": true, @@ -10470,12 +16451,37 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/retry": { "version": "0.13.1", "dev": true, @@ -10486,7 +16492,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -10537,9 +16542,16 @@ "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", "dev": true }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", - "dev": true, "funding": [ { "type": "github", @@ -10559,19 +16571,52 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/safari-14-idb-fix": { "version": "3.0.0", "license": "Apache-2.0" }, "node_modules/safe-buffer": { "version": "5.1.2", - "dev": true, "license": "MIT" }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "license": "MIT" + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "optional": true }, "node_modules/saxes": { "version": "6.0.0", @@ -10659,7 +16704,6 @@ }, "node_modules/semver": { "version": "7.5.4", - "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -10859,9 +16903,43 @@ "node": ">=8" } }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sharp/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" + }, "node_modules/shebang-command": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -10872,7 +16950,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10923,9 +17000,64 @@ }, "node_modules/signal-exit": { "version": "3.0.5", - "dev": true, "license": "ISC" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/simultaneous-cursors": { "resolved": "examples/simultaneous-cursors", "link": true @@ -10951,7 +17083,6 @@ }, "node_modules/slash": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10983,6 +17114,7 @@ }, "node_modules/sourcemap-codec": { "version": "1.4.8", + "dev": true, "license": "MIT" }, "node_modules/spdx-exceptions": { @@ -11050,6 +17182,23 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -11122,9 +17271,17 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", + "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/string_decoder": { "version": "1.1.1", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -11139,13 +17296,27 @@ } }, "node_modules/string-width": { - "version": "4.2.2", - "dev": true, - "license": "MIT", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" @@ -11177,7 +17348,6 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -11186,9 +17356,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11242,9 +17423,80 @@ } } }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "5.5.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -11264,6 +17516,94 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svelte": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.0.1.tgz", + "integrity": "sha512-7n2u7A5cu8xCY6MBiXh/Mg6Lh3+Mw2qXlTDBYhzvCvmSM4L4gc4MVo540UtGcjqBiA48E1VDW+EUpBr7iuBlPg==", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^3.2.1", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.0", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/svelte/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/svelte/node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", + "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==", + "optional": true, + "peer": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -11278,9 +17618,76 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/terser": { "version": "5.19.2", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -11355,7 +17762,7 @@ }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.20", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -11381,6 +17788,25 @@ "dev": true, "license": "MIT" }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thunky": { "version": "1.1.0", "dev": true, @@ -11397,6 +17823,11 @@ "node": ">=0.6.0" } }, + "node_modules/timsort": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", + "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==" + }, "node_modules/tiny-warning": { "version": "1.0.3", "license": "MIT" @@ -11425,6 +17856,17 @@ "node": ">=14.0.0" } }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-fast-properties": { "version": "1.0.3", "dev": true, @@ -11435,7 +17877,6 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -11500,6 +17941,14 @@ "node": ">=14" } }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/trim-right": { "version": "1.0.1", "dev": true, @@ -11508,6 +17957,16 @@ "node": ">=0.10.0" } }, + "node_modules/ts-algebra": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-1.2.2.tgz", + "integrity": "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==" + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, "node_modules/ts-loader": { "version": "9.3.1", "dev": true, @@ -11528,7 +17987,7 @@ }, "node_modules/ts-node": { "version": "10.9.1", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -11570,7 +18029,7 @@ }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -11645,6 +18104,187 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsup": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-7.2.0.tgz", + "integrity": "sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==", + "dependencies": { + "bundle-require": "^4.0.0", + "cac": "^6.7.12", + "chokidar": "^3.5.1", + "debug": "^4.3.1", + "esbuild": "^0.18.2", + "execa": "^5.0.0", + "globby": "^11.0.3", + "joycon": "^3.0.1", + "postcss-load-config": "^4.0.1", + "resolve-from": "^5.0.0", + "rollup": "^3.2.5", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.20.3", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/bundle-require": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-4.0.2.tgz", + "integrity": "sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.17" + } + }, + "node_modules/tsup/node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/tsup/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tsup/node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tsup/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tsup/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tsup/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/tsup/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "node_modules/tsutils": { "version": "3.21.0", "dev": true, @@ -11664,6 +18304,17 @@ "dev": true, "license": "MIT" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "dev": true, @@ -11685,7 +18336,6 @@ }, "node_modules/type-fest": { "version": "0.20.2", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -11749,6 +18399,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unique-names-generator": { "version": "4.7.1", "license": "MIT", @@ -11756,6 +18412,20 @@ "node": ">=8" } }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/universalify": { "version": "0.1.2", "dev": true, @@ -11774,7 +18444,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.0.11", - "dev": true, "funding": [ { "type": "opencollective", @@ -11868,6 +18537,18 @@ } } }, + "node_modules/use-resize-observer": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", + "integrity": "sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==", + "dependencies": { + "@juggle/resize-observer": "^3.3.1" + }, + "peerDependencies": { + "react": "16.8.0 - 18", + "react-dom": "16.8.0 - 18" + } + }, "node_modules/use-sidecar": { "version": "1.1.2", "license": "MIT", @@ -11914,9 +18595,16 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, "license": "MIT" }, + "node_modules/utility-types": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", + "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "dev": true, @@ -11940,7 +18628,7 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -12308,14 +18996,15 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.2.45", - "license": "MIT", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz", + "integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==", "dependencies": { - "@vue/compiler-dom": "3.2.45", - "@vue/compiler-sfc": "3.2.45", - "@vue/runtime-dom": "3.2.45", - "@vue/server-renderer": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-sfc": "3.3.4", + "@vue/runtime-dom": "3.3.4", + "@vue/server-renderer": "3.3.4", + "@vue/shared": "3.3.4" } }, "node_modules/vuejs-kanban": { @@ -12357,6 +19046,19 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==" + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -12738,7 +19440,6 @@ }, "node_modules/which": { "version": "2.0.2", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -12829,6 +19530,53 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, @@ -12861,7 +19609,6 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, "license": "ISC" }, "node_modules/ws": { @@ -12908,11 +19655,23 @@ "node": ">=0.4" } }, + "node_modules/xxhash-wasm": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz", + "integrity": "sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==" + }, "node_modules/yallist": { "version": "4.0.0", - "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/yargs": { "version": "17.0.1", "dev": true, @@ -12948,16 +19707,20 @@ }, "node_modules/yn": { "version": "3.1.1", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/yorkie-devtools": { + "resolved": "tools/devtools", + "link": true + }, "node_modules/yorkie-js-sdk": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.12.tgz", - "integrity": "sha512-V0NM423hmJ5NaFDRJgEgnWgr1Nd8rqy7SZoZ3uu5TBJIlDgbX6HOEjPWWUopnBdD/WFAeiycOYAbNFD6sdHt8A==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.7.tgz", + "integrity": "sha512-bUe2f11TTAxV5nsSvozFNGiiHiVhZy03IGbHWwUxsuGa/JluGQOhlqDuyPLEmaPe62YRJlbbBXJ4WAczTjObaA==", "dependencies": { "@types/google-protobuf": "^3.15.5", "@types/long": "^4.0.1", @@ -13033,6 +19796,76 @@ "minimist": "^1.2.8", "prompts": "^2.4.2" } + }, + "tools/devtools": { + "version": "0.0.1", + "dependencies": { + "classnames": "^2.3.2", + "plasmo": "0.84.0", + "prism-react-renderer": "^2.3.1", + "react": "18.2.0", + "react-arborist": "^3.4.0", + "react-dom": "18.2.0", + "use-resize-observer": "^9.1.0", + "yorkie-js-sdk": "0.4.13-rc" + }, + "devDependencies": { + "@types/chrome": "0.0.251", + "@types/node": "20.9.0", + "@types/react": "18.2.37", + "@types/react-dom": "18.2.15", + "prettier": "3.0.3", + "typescript": "5.2.2" + } + }, + "tools/devtools/node_modules/@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "tools/devtools/node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "tools/devtools/node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "tools/devtools/node_modules/yorkie-js-sdk": { + "version": "0.4.13-rc", + "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.13-rc.tgz", + "integrity": "sha512-T/0giRrkyX+qrNLZ/yvvJaMA1Roc7veykQ+5u6FliLYZYU4jyZt2+dSOs/6tLpWZO6WNf06wXDtn6vAtxI1TgQ==", + "dependencies": { + "@types/google-protobuf": "^3.15.5", + "@types/long": "^4.0.1", + "google-protobuf": "^3.19.4", + "grpc-web": "^1.3.1", + "long": "^5.2.0" + } } } } diff --git a/package.json b/package.json index cc35eb336..8c4117d2f 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "build:docs": "npm run predoc && api-documenter markdown --input temp --output docs", "build:examples": "npm run build --workspace examples", "build:create-yorkie-app": "npm run build --workspace create-yorkie-app", + "build:devtools": "npm run build --workspace tools/devtools", "build:ghpages": "mkdir -p ghpages/examples && cp -r docs ghpages/api-reference && find examples -name 'dist' -type d -exec sh -c 'cp -r {} ghpages/examples/$(basename $(dirname {}))' \\;", "api-report": "api-extractor run --local --verbose --config ./config/api-extractor.json", "prune": "ts-node-script ./scripts/prune-dts.ts --input ./dist/yorkie-js-sdk.d.ts --output ./dist/yorkie-js-sdk.d.ts", diff --git a/public/devtool/object.js b/public/devtool/object.js index 994786f23..4f196f014 100644 --- a/public/devtool/object.js +++ b/public/devtool/object.js @@ -11,7 +11,7 @@ const objectDevtool = ( `; }; - const renderContainer = ({ key, value, id }) => { + const renderContainer = ({ key, value, createdAt }) => { const valueHTML = Object.values(value) .map((v) => { return v.type === 'YORKIE_OBJECT' || v.type === 'YORKIE_ARRAY' @@ -22,7 +22,7 @@ const objectDevtool = ( if (key === undefined) key = 'root'; return `
- ${renderKey({ key, id })} + ${renderKey({ key, createdAt })}
${valueHTML}
@@ -30,20 +30,20 @@ const objectDevtool = ( `; }; - const renderKey = ({ key, id }) => { + const renderKey = ({ key, createdAt }) => { return ` - -
extends CRDTGCElement { */ public toJSForTest(): Devtools.JSONElement { return { - id: this.getCreatedAt().toTestString(), + createdAt: this.getCreatedAt().toTestString(), value: JSON.parse(this.toJSON()), type: 'YORKIE_TEXT', }; diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index 8934defa6..d8de4d185 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -39,7 +39,7 @@ import type { TreeToken, } from '@yorkie-js-sdk/src/util/index_tree'; import { Indexable } from '@yorkie-js-sdk/src/document/document'; -import type * as Devtools from '@yorkie-js-sdk/src/types/devtools_element'; +import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; /** * `TreeNode` represents a node in the tree. @@ -350,6 +350,14 @@ export class CRDTTreeNodeID { public toIDString(): string { return `${this.createdAt.toIDString()}:${this.offset}`; } + + /** + * `toTestString` returns a string containing the meta data of the ticket + * for debugging purpose. + */ + public toTestString(): string { + return `${this.createdAt.toTestString()}:${this.offset}`; + } } /** @@ -1088,15 +1096,54 @@ export class CRDTTree extends CRDTGCElement { /** * `toJSForTest` returns value with meta data for testing. + * + * @internal */ public toJSForTest(): Devtools.JSONElement { return { - id: this.getCreatedAt().toTestString(), + createdAt: this.getCreatedAt().toTestString(), value: JSON.parse(this.toJSON()), type: 'YORKIE_TREE', }; } + /** + * `toJSInfoForTest` returns detailed TreeNode information for use in Devtools. + * + * @internal + */ + public toJSInfoForTest(): Devtools.TreeNodeInfo { + const rootNode = this.indexTree.getRoot(); + + const toTreeNodeInfo = ( + node: CRDTTreeNode, + parentID: string | undefined = undefined, + depth = 0, + ): Devtools.TreeNodeInfo => { + const nodeInfo: Devtools.TreeNodeInfo = { + type: node.type, + parent: parentID, + size: node.size, + id: node.id.toTestString(), + removedAt: node.removedAt?.toTestString(), + insPrev: node.insPrevID?.toTestString(), + insNext: node.insNextID?.toTestString(), + value: node.isText ? node.value : undefined, + isRemoved: node.isRemoved, + children: [] as Array, + depth, + }; + + for (const child of node.children) { + nodeInfo.children.push(toTreeNodeInfo(child, nodeInfo.id, depth + 1)); + } + + return nodeInfo; + }; + + return toTreeNodeInfo(rootNode); + } + /** * `getRootTreeNode` returns the converted value of this tree to TreeNode. */ diff --git a/src/document/document.ts b/src/document/document.ts index 9ad0e1dac..ac64284c7 100644 --- a/src/document/document.ts +++ b/src/document/document.ts @@ -68,6 +68,8 @@ import { PresenceChangeType, } from '@yorkie-js-sdk/src/document/presence/presence'; import { History, HistoryOperation } from '@yorkie-js-sdk/src/document/history'; +import { setupDevtools } from '@yorkie-js-sdk/src/devtools'; +import * as Devtools from '@yorkie-js-sdk/src/devtools/types'; /** * `DocumentOptions` are the options to create a new document. @@ -470,6 +472,8 @@ export class Document { undo: this.undo.bind(this), redo: this.redo.bind(this), }; + + setupDevtools(this); } /** @@ -1018,6 +1022,16 @@ export class Document { return this.root.toSortedJSON(); } + /** + * `toJSForTest` returns value with meta data for testing. + */ + public toJSForTest(): Devtools.JSONElement { + return { + ...this.getRoot().toJSForTest!(), + key: 'root', + }; + } + /** * `applySnapshot` applies the given snapshot into this document. */ @@ -1242,6 +1256,31 @@ export class Document { return presences; } + /** + * `getSelfForTest` returns the client that has attached this document. + * + * @internal + */ + public getSelfForTest() { + return { + clientID: this.getChangeID().getActorID()!, + presence: this.getMyPresence(), + }; + } + + /** + * `getOthersForTest` returns all the other clients in online, sorted by clientID. + * + * @internal + */ + public getOthersForTest() { + const myClientID = this.getChangeID().getActorID()!; + + return this.getPresences() + .filter((a) => a.clientID !== myClientID) + .sort((a, b) => (a.clientID > b.clientID ? 1 : -1)); + } + /** * `canUndo` returns whether there are any operations to undo. */ diff --git a/src/document/json/object.ts b/src/document/json/object.ts index e594d13da..7f15a686d 100644 --- a/src/document/json/object.ts +++ b/src/document/json/object.ts @@ -26,6 +26,7 @@ import { toJSONElement, buildCRDTElement, } from '@yorkie-js-sdk/src/document/json/element'; +import * as Devtools from '@yorkie-js-sdk/src/devtools/types'; /** * `JSONObject` represents a JSON object, but unlike regular JSON, it has time @@ -46,6 +47,11 @@ export type JSONObject = { * `toJS` returns the JSON object of this object. */ toJS?(): T; + + /** + * `toJSForTest` returns the JSON object of this object for debugging. + */ + toJSForTest?(): Devtools.JSONElement; } & T; /** diff --git a/src/document/json/tree.ts b/src/document/json/tree.ts index 3b3af5f19..8cd2ee4f8 100644 --- a/src/document/json/tree.ts +++ b/src/document/json/tree.ts @@ -42,6 +42,7 @@ import type { TreePosStructRange, CRDTTreeNodeIDStruct, } from '@yorkie-js-sdk/src/document/crdt/tree'; +import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; /** * NOTE(hackerwins): In normal case, we should define the following types in @@ -518,6 +519,19 @@ export class Tree { return this.tree.toJSON(); } + /** + * `toJSInfoForTest` returns detailed TreeNode information for use in Devtools. + * + * @internal + */ + public toJSInfoForTest(): Devtools.TreeNodeInfo { + if (!this.context || !this.tree) { + throw new Error('it is not initialized yet'); + } + + return this.tree.toJSInfoForTest(); + } + /** * `getRootTreeNode` returns TreeNode of this tree. */ diff --git a/src/types/devtools_element.ts b/src/types/devtools_element.ts deleted file mode 100644 index 6e87f4d9d..000000000 --- a/src/types/devtools_element.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { PrimitiveValue } from '@yorkie-js-sdk/src/document/crdt/primitive'; -import { CounterValue } from '@yorkie-js-sdk/src/document/crdt/counter'; - -// NOTE(chacha912): Json type is used to represent CRDTText and CRDTTree value. -// In the dev tool, display value as the result of toJSON for CRDTText and CRDTTree. -export type Json = - | string - | number - | boolean - // eslint-disable-next-line @typescript-eslint/ban-types - | null - | { [key: string]: Json } - | Array; - -export type ContainerValue = { - [key: string]: JSONElement; -}; - -type ElementValue = - | PrimitiveValue - | CounterValue - | ContainerValue // Array | Object - | Json; // Text | Tree - -export type ElementType = - | 'YORKIE_PRIMITIVE' - | 'YORKIE_COUNTER' - | 'YORKIE_OBJECT' - | 'YORKIE_ARRAY' - | 'YORKIE_TEXT' - | 'YORKIE_TREE'; - -export type JSONElement = { - id: string; - key?: string; - value: ElementValue; - type: ElementType; -}; diff --git a/src/yorkie.ts b/src/yorkie.ts index 2b6b46451..5198daefd 100644 --- a/src/yorkie.ts +++ b/src/yorkie.ts @@ -87,6 +87,7 @@ export { export { JSONObject } from '@yorkie-js-sdk/src/document/json/object'; export { JSONArray } from '@yorkie-js-sdk/src/document/json/array'; export { Counter } from '@yorkie-js-sdk/src/document/json/counter'; +export { CounterValue } from '@yorkie-js-sdk/src/document/crdt/counter'; export { Text, TextPosStruct, diff --git a/tools/devtools/.gitignore b/tools/devtools/.gitignore new file mode 100644 index 000000000..54afb48bb --- /dev/null +++ b/tools/devtools/.gitignore @@ -0,0 +1,33 @@ + +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +out/ +build/ +dist/ + +# plasmo +.plasmo + +# typescript +.tsbuildinfo diff --git a/tools/devtools/README.md b/tools/devtools/README.md new file mode 100644 index 000000000..111153965 --- /dev/null +++ b/tools/devtools/README.md @@ -0,0 +1,18 @@ +# Yorkie Devtools + +Yorkie Devtools is a Chrome extension designed to assist in debugging Yorkie. + +Yorkie Devtools + +## Installation + +Note: Installation instructions are coming soon. + +## Development + +To start developing with Yorkie Devtools, follow these steps: + +1. Run `npm run build` from this directory. +2. Open your Chrome browser and go to [chrome://extensions](chrome://extensions). +3. Enable "Developer mode." +4. Click on "Load unpacked" and select the output directory `dist/chrome-mv3-prod`. diff --git a/tools/devtools/assets/icon.png b/tools/devtools/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0dd2ba6f208e753ba021cc2c31283af85d6fb2ab GIT binary patch literal 2067 zcmaKt`8(7L8^*tbv5f7+SaOKOL2AY}S+b3F%veI!#&(n?Ylws~mX4yuM7Ct#Mwr(g zlcBt6XozfYF-8(*H1x_o;^_PV=ee%?xv$TC|M2|y+`D9NEew%?001CtgR*cscKk2# z^B(VhW50LDCJ>48hz0;b@m~S~Ma9y`At>6(+6-tKk!2nOPax6`2>{KH1P}bc0Kivg zV}ZPU3&f_sj}W(p@_pZlWk)t}q$Xs8x+aws9LJoNdBc>7dx2d+yuX7$GIAcSaKQaw zrb1qP{&m^*?oCgj$%z#F}@tqT|w%c zdG3{IssqY?c3>PwyV&HsqI2`6i^H4WcmymJKYrd*wWnyTN5h@L@Jt~EL}~D7IWHY<1roM=qUY^ob8>UA0I84_?HtJ`kR&iP1^xQ!V@mfME{- z)Fugf#tML%iNi0Y>#TC1FM?!{+6?SmW{s$V?Y_^!jju{zSdk{aX+y};!XO2jlB?L< zwa1aKHPPQ1s%pSM^~Qm2`k`OD-HE&5h{%BbmKdI=(0Y{95oM(&rR75aZd28^$NdXf1>;eSAh3!IP=xbOxw0+re6A|TT?aADMZd$ zmrgaaFQ?Q?!`_gh{tOSzf_boxIFkC=@6}764upoLnd$@A7vTEwEx{EXI{_DRKg6j^ zmBQU$LfdQLh{6|}a^|p$xXnr{=V*iH3?biyrL@i*HY==TpNLWZ9RsY4>~)u{#L?P_ zhb7jt=-yknjB{-@aE7M*67LhG)$Q}75f7u~!9tJf_}ysQP`N-Vu_di+6Zqd+aY&Vm zvfC;_jUih{WaalZ5bhK*Nj?SrvkDB^?j*6z`cDjl4dfsEyty=6>~4G-+KDA?N^xY1iO1KP7j8@O6oLt}Kb2OT)Z~eJge55ev>T&J>oNAt6u23*&!| z8Gr3c8LzT8B6!lTwYotd?04iC4y`O=L~%>hzh)?jgq%kJG*Hm8A#n1COyjFB+PYyS zh-CMlgWw3lE!Eq?eBSH#M^$Etey?S+6f zSb4wM`*2p^bI`Z3h?JszrpL5XloA}IFm^QeR|dI={UrOmbn}P{WN~k*68FP6i<-z+ zD8d{*tZcPA>;4&ZDP~jtc38Bsdp_5AJ>oqXBeEDj)##nG*H)VZfpIVR`{Y1e`}&rp z4I_-KV?8vq9!0=O?%*p^Y<1%wa=YN|9>N!>46yH4X=y2x_>l0}v#m?4#mTp;arR0l zytV>^YzAf5c=MiJKUBp#(b|J|N!`M@~c zBxr>eJr52TiVG2<8@nM~Y#Mlp{ZJ>aiJZYkO}X^@t~$q6HOAAbsv?3` zc`f0k75WgAS-s`MjXXS-`IcJ^3?oNaYSTwR3Rj+~ws9jp(4o7Y2IpI6 z0*M{YL_PND7!kmps?XkC@@GzP%pB~SuJsuK1(XWBL|04^eZb|lnFFjwD4V+$$o8V7 z)V$Ws#2Pdnp1jU7p)$SAYXQ^;WUwx5(a}PU8moIEU#o|P5f)q3nuh{4Kc=ftN)1w8 zm{%_(yNa8C=3gg+0n05mJ>YtQft|29bNhkq#|X=42;em!TmX(@=1Fukl5Is8RV)L+ z?>O#&F{de4qM?mmQ_ecIndee)CtS)>#v<=ggwxf<-lj7cdyvMc?3cKO`-XN}X#<2) zQZm}B%@pw=HQ=gzNv0DL(nbCWi|vrI${8>V50N zMu5XsP!uNPXlrxBBrhCg)j^jflg#vOZNsSU^IN!t9vo%PEloz<%fFFzj!(l+;J)as zI0F~$b_B;pd7L}!Npq|_!|vX@k4rfBN9}8c`aQFsXAwuZYq0f_k?_#ZCFq=RgiXRh zye7F6G9wutlIu%2I)~PtR#RzDxI-f-Yu_x!oC_4~FA)Dk|B2C8nPl}i@>Jzam)1@B z@MT?iMWD(buH5w { + const message = event.data as Record; + if (message?.source === EventSourceSDK) { + if (!panelPort) return; + panelPort.postMessage(message as FullSDKToPanelMessage); + } +}); + +// Relay messages received from the Devtools panel to the SDK. +// TODO(hackerwins): We need to ensure that this event listener should be +// removed later. +chrome.runtime.onConnect.addListener((port) => { + if (port.name !== EventSourceDevPanel) { + return; + } + panelPort = port; + const handleMessage = (message) => { + window.postMessage(message, '*'); + }; + + port.onMessage.addListener(handleMessage); + port.onDisconnect.addListener(() => { + panelPort.onMessage.removeListener(handleMessage); + panelPort = null; + window.postMessage({ + source: EventSourceDevPanel, + msg: 'devtools::disconnect', + }); + }); +}); diff --git a/tools/devtools/src/devtools/components/Code.tsx b/tools/devtools/src/devtools/components/Code.tsx new file mode 100644 index 000000000..71e5038cc --- /dev/null +++ b/tools/devtools/src/devtools/components/Code.tsx @@ -0,0 +1,92 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Language, PrismTheme } from 'prism-react-renderer'; +import { Highlight } from 'prism-react-renderer'; + +const theme: PrismTheme = { + plain: {}, + styles: [ + { + types: [ + 'comment', + 'prolog', + 'doctype', + 'cdata', + 'punctuation', + 'namespace', + 'operator', + 'tag', + 'number', + 'property', + 'function', + 'tag-id', + 'selector', + 'atrule-id', + 'attr-name', + 'string', + 'boolean', + 'entity', + 'url', + 'attr-value', + 'keyword', + 'control', + 'directive', + 'unit', + 'statement', + 'regex', + 'atrule', + 'placeholder', + 'variable', + 'deleted', + 'inserted', + 'italic', + 'important', + 'bold', + ], + style: {}, + }, + ], +}; + +export function Code({ + code, + language, + withLineNumbers, +}: { + code: string; + language: Language; + withLineNumbers?: boolean; +}) { + return ( + + {({ className, tokens, getLineProps, getTokenProps }) => ( +
+          {tokens.map((line, i) => (
+            
+ {withLineNumbers && {i + 1}} + + {line.map((token, key) => ( + + ))} + +
+ ))} +
+ )} +
+ ); +} diff --git a/tools/devtools/src/devtools/components/Detail.tsx b/tools/devtools/src/devtools/components/Detail.tsx new file mode 100644 index 000000000..6e46de005 --- /dev/null +++ b/tools/devtools/src/devtools/components/Detail.tsx @@ -0,0 +1,125 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import classNames from 'classnames'; +import { useState, useCallback } from 'react'; + +import { Code } from './Code'; +import type { RootTreeNode } from './Tree'; +import { CodeIcon, GraphIcon } from '../icons'; +import type { TreeNodeInfo } from '../../protocol'; + +type FlatTreeNodeInfo = TreeNodeInfo & { + depth: number; + childIndex: number; +}; + +function TreeNode({ node }: { node: FlatTreeNodeInfo }) { + if (node.type === 'text') { + // NOTE(chacha912): The 'depth' variable is used for styling purposes. + // For 'text' nodes, when they are not the first child node, 'depth' is + // set to 0 to ensure they are displayed on the same line. + const depth = node.childIndex === 0 ? node.depth : 0; + + return ( +
+ + {node.value} + {node.id} + +
+ ); + } + + return ( +
+ + {node.type} + {node.id} + +
+ ); +} + +function TreeGraph({ tree }: { tree: TreeNodeInfo }) { + const flattenTreeWithDepth = useCallback( + (node: TreeNodeInfo, depth = 0, i = 0): Array => { + const nodeWithDepth = { ...node, depth, childIndex: i }; + const children = (node.children || []).flatMap((child, i) => + flattenTreeWithDepth(child, depth + 1, i), + ); + return [nodeWithDepth, ...children]; + }, + [], + ); + + return flattenTreeWithDepth(tree).map((node) => ( + + )); +} + +export function TreeDetail({ + node, + tree, +}: { + node: RootTreeNode; + tree: TreeNodeInfo; +}) { + const [viewType, setViewType] = useState<'json' | 'graph'>('json'); + + return ( +
+
+ + +
+ {viewType === 'json' && ( + + )} + {viewType === 'graph' && tree && } +
+ ); +} + +export function JSONDetail({ json }: { json: string }) { + return ; +} diff --git a/tools/devtools/src/devtools/components/Tree.tsx b/tools/devtools/src/devtools/components/Tree.tsx new file mode 100644 index 000000000..f3b9751f6 --- /dev/null +++ b/tools/devtools/src/devtools/components/Tree.tsx @@ -0,0 +1,345 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import classNames from 'classnames'; +import { useEffect, useMemo } from 'react'; +import { Tree as ArboristTree } from 'react-arborist'; +import type { NodeRendererProps } from 'react-arborist'; +import useResizeObserver from 'use-resize-observer'; + +import { useSeletedNode } from '../contexts/SeletedNode'; +import { useSeletedPresence } from '../contexts/SeletedPresence'; +import { sendToSDK } from '../../port'; +import type { + Client, + JSONElement, + ElementValue, + ElementType, + Json, +} from '../../protocol'; + +import { + ArrayIcon, + CounterIcon, + ObjectIcon, + PrimitiveIcon, + TextIcon, + TreeIcon, + UserIcon, +} from '../icons'; + +export type RootTreeNode = { + id: string; + path: string; + key: string; + createdAt: string; + value: ElementValue; + type: ElementType; + isLastChild?: boolean; +}; + +type UserNode = { + clientID: string; + presence: Json; + id: string; + type: 'USER'; +}; +type PresenceJsonNode = { + id: string; + key: string; + value: Json; + isLastChild: boolean; + type: 'JSON'; +}; +export type PresenceTreeNode = UserNode | PresenceJsonNode; + +const RootPath = '$'; +const RowHeight = 42; +const RowIndent = 22; + +const TypeIcon = ({ type }) => { + switch (type) { + case 'YORKIE_OBJECT': + return ; + case 'YORKIE_ARRAY': + return ; + case 'YORKIE_PRIMITIVE': + return ; + case 'YORKIE_TEXT': + return ; + case 'YORKIE_TREE': + return ; + case 'YORKIE_COUNTER': + return ; + case 'USER': + return ; + default: + return null; + } +}; + +/** + * `RootNodeRenderer` handles the rendering of root nodes + */ +function RootNodeRenderer(props: NodeRendererProps) { + const type = props.node.data.type.split('YORKIE_')[1].toLowerCase(); + const [selectedNode, setSelectedNode] = useSeletedNode(); + + useEffect(() => { + if (selectedNode?.id === props.node.data.id) { + // NOTE(chacha912): When the document changes, also update the currently selected node. + setSelectedNode(props.node.data); + + if (props.node.data.type === 'YORKIE_TREE') { + sendToSDK({ + msg: 'devtools::node::detail', + data: { + path: props.node.data.path, + type: props.node.data.type, + }, + }); + } + } + }, [props.node.data]); + + switch (props.node.data.type) { + case 'YORKIE_OBJECT': + case 'YORKIE_ARRAY': + return ( +
props.node.toggle()} + className="tree-wrap" + > + + {props.node.isOpen ? '▾' : '▸'} + + + + {props.node.data.key} + {props.node.data.createdAt} + +
+ ); + default: + return ( +
{ + if (props.node.data?.id === selectedNode?.id) { + return; + } + setSelectedNode(props.node.data); + }} + className="tree-wrap" + > + + + + + {props.node.data.key} :  + + {JSON.stringify(props.node.data.value)} + + {props.node.data.createdAt} + +
+ ); + } +} + +/** + * `PresenceNodeRenderer` handles the rendering of presence nodes + */ +function PresenceNodeRenderer(props: NodeRendererProps) { + const [selectedPresence, setSelectedPresence] = useSeletedPresence(); + + useEffect(() => { + if (selectedPresence?.id === props.node.data.id) { + //NOTE(chacha912): When the presence changes, also update the currently selected presence. + setSelectedPresence(props.node.data); + } + }, [props.node.data]); + + switch (props.node.data.type) { + case 'USER': + return ( +
props.node.toggle()} + className="tree-wrap" + > + + {props.node.isOpen ? '▾' : '▸'} + + + + {props.node.data.clientID} + +
+ ); + case 'JSON': + return ( +
{ + if (props.node.data?.id === selectedPresence?.id) { + return; + } + setSelectedPresence(props.node.data); + }} + className="tree-wrap" + > + + {props.node.data.key} :  + + {JSON.stringify(props.node.data.value)} + + +
+ ); + default: + return null; + } +} + +/** + * `rootChildAccessor` returns the children of the document node. + */ +function rootChildAccessor(node: RootTreeNode): Array { + if (!(node.type === 'YORKIE_OBJECT' || node.type === 'YORKIE_ARRAY')) { + return null; + } + const children = Object.values(node.value) as Array; + const length = children.length; + const res = children.map((v, i) => { + const path = `${node.path}.${v.key}`; + if (v.type === 'YORKIE_OBJECT' || v.type === 'YORKIE_ARRAY') { + return { + ...v, + id: path, + path, + isLastChild: i === length - 1, + }; + } else { + return { + ...v, + id: path, + path, + isLastChild: i === length - 1, + }; + } + }); + return res; +} + +/** + * `presenceChildAccessor` returns the children of the presence node. + */ +function presenceChildAccessor( + node: PresenceTreeNode, +): Array { + if (node.type !== 'USER') return null; + const length = Object.keys(node.presence).length; + return Object.keys(node.presence) + .sort() + .map((key, i) => ({ + key, + value: node.presence[key], + id: `${node.clientID}-${key}`, + type: 'JSON', + isLastChild: i === length - 1, + })); +} + +/** + * `PresenceTree` renders the presences of the document. + */ +export function PresenceTree({ presences }: { presences: Array }) { + const { ref, width, height } = useResizeObserver(); + const data = useMemo(() => { + const presenceNodes: Array = presences.map((client) => ({ + ...client, + id: client.clientID, + type: 'USER', + })); + return presenceNodes; + }, [presences]); + + return ( +
+ + {PresenceNodeRenderer} + +
+ ); +} + +/** + * `RootTree` renders the root object of the document. + */ +export function RootTree({ root }: { root: JSONElement }) { + const { ref, width, height } = useResizeObserver(); + const data = useMemo(() => { + const rootNode: Array = root + ? [{ ...root, id: RootPath, path: RootPath }] + : []; + return rootNode; + }, [root]); + + return ( +
+ + {RootNodeRenderer} + +
+ ); +} diff --git a/tools/devtools/src/devtools/contexts/SeletedNode.tsx b/tools/devtools/src/devtools/contexts/SeletedNode.tsx new file mode 100644 index 000000000..183ee492f --- /dev/null +++ b/tools/devtools/src/devtools/contexts/SeletedNode.tsx @@ -0,0 +1,43 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ReactNode } from 'react'; +import { createContext, useContext, useState } from 'react'; +import type { RootTreeNode } from '../components/Tree'; + +type SelectedNodeContext = [RootTreeNode, (node: RootTreeNode) => void]; +const SelectedNodeContext = createContext(null); + +type Props = { + children?: ReactNode; +}; +export function SeleteNodeProvider({ children }: Props) { + const selectedNodeState = useState(null); + + return ( + + {children} + + ); +} + +export function useSeletedNode() { + const value = useContext(SelectedNodeContext); + if (value === undefined) { + throw new Error('useSeletedNode should be used within SeleteNodeProvider'); + } + return value; +} diff --git a/tools/devtools/src/devtools/contexts/SeletedPresence.tsx b/tools/devtools/src/devtools/contexts/SeletedPresence.tsx new file mode 100644 index 000000000..d72c079b2 --- /dev/null +++ b/tools/devtools/src/devtools/contexts/SeletedPresence.tsx @@ -0,0 +1,50 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ReactNode } from 'react'; +import { createContext, useContext, useState } from 'react'; +import type { PresenceTreeNode } from '../components/Tree'; + +type SelectedPresenceContext = [ + PresenceTreeNode, + (node: PresenceTreeNode) => void, +]; +const SelectedPresenceContext = createContext( + null, +); + +type Props = { + children?: ReactNode; +}; +export function SeletedPresenceProvider({ children }: Props) { + const selectedPresenceState = useState(null); + + return ( + + {children} + + ); +} + +export function useSeletedPresence() { + const value = useContext(SelectedPresenceContext); + if (value === undefined) { + throw new Error( + 'useSeletedPresence should be used within SeletedPresenceProvider', + ); + } + return value; +} diff --git a/tools/devtools/src/devtools/contexts/YorkieSource.tsx b/tools/devtools/src/devtools/contexts/YorkieSource.tsx new file mode 100644 index 000000000..41fee9c8b --- /dev/null +++ b/tools/devtools/src/devtools/contexts/YorkieSource.tsx @@ -0,0 +1,131 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ReactNode } from 'react'; +import { + createContext, + useCallback, + useContext, + useEffect, + useState, +} from 'react'; + +import type { + JSONElement, + Client, + SDKToPanelMessage, + TreeNodeInfo, +} from '../../protocol'; +import { onPortMessage, sendToSDK } from '../../port'; + +const DocKeyContext = createContext(null); +const RootContext = createContext(null); +const PresencesContext = createContext | null>(null); +const NodeDetailContext = createContext(null); + +type Props = { + children?: ReactNode; +}; + +export function YorkieSourceProvider({ children }: Props) { + const [currentDocKey, setCurrentDocKey] = useState(''); + const [root, setRoot] = useState(null); + const [presences, setPresences] = useState>([]); + const [nodeDetail, setNodeDetail] = useState(null); + + const handleSDKMessage = useCallback((message: SDKToPanelMessage) => { + switch (message.msg) { + case 'doc::available': + setCurrentDocKey(message.docKey); + sendToSDK({ + msg: 'devtools::subscribe', + docKey: message.docKey, + }); + break; + case 'doc::sync::full': + setRoot(message.root); + setPresences(message.clients); + break; + case 'doc::sync::partial': + if (message.root) { + setRoot(message.root); + } + if (message.clients) { + setPresences(message.clients); + } + break; + case 'doc::node::detail': + setNodeDetail(message.node); + break; + } + }, []); + + useEffect(() => { + sendToSDK({ msg: 'devtools::connect' }); + onPortMessage.addListener(handleSDKMessage); + return () => { + onPortMessage.removeListener(handleSDKMessage); + }; + }, []); + + return ( + + + + + {children} + + + + + ); +} + +export function useCurrentDocKey() { + const value = useContext(DocKeyContext); + if (value === undefined) { + throw new Error( + 'useCurrentDocKey should be used within YorkieSourceProvider', + ); + } + return value; +} + +export function useDocumentRoot() { + const value = useContext(RootContext); + if (value === undefined) { + throw new Error( + 'useDocumentRoot should be used within YorkieSourceProvider', + ); + } + return value; +} + +export function usePresences() { + const value = useContext(PresencesContext); + if (value === undefined) { + throw new Error('usePresences should be used within YorkieSourceProvider'); + } + return value; +} + +export function useNodeDetail() { + const value = useContext(NodeDetailContext); + if (value === undefined) { + throw new Error('useNodeDetail should be used within YorkieSourceProvider'); + } + return value; +} diff --git a/tools/devtools/src/devtools/icons/index.tsx b/tools/devtools/src/devtools/icons/index.tsx new file mode 100644 index 000000000..506bd98b9 --- /dev/null +++ b/tools/devtools/src/devtools/icons/index.tsx @@ -0,0 +1,207 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ComponentProps } from 'react'; + +export function ObjectIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function ArrayIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function PrimitiveIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function TextIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function TreeIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function CounterIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function UserIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function CloseIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function CodeIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} + +export function GraphIcon(props: ComponentProps<'svg'>) { + return ( + + + + ); +} diff --git a/tools/devtools/src/devtools/index.tsx b/tools/devtools/src/devtools/index.tsx new file mode 100644 index 000000000..28c30dea0 --- /dev/null +++ b/tools/devtools/src/devtools/index.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import yorkiePanelHTML from 'url:./panel/index.html'; + +chrome.devtools.panels.create( + '🐶 Yorkie', + '', + // See: https://github.com/PlasmoHQ/plasmo/issues/106#issuecomment-1188539625 + yorkiePanelHTML.split('/').pop(), +); + +function Page() { + return null; +} + +export default Page; diff --git a/tools/devtools/src/devtools/panel/code.css b/tools/devtools/src/devtools/panel/code.css new file mode 100644 index 000000000..0a49fbd61 --- /dev/null +++ b/tools/devtools/src/devtools/panel/code.css @@ -0,0 +1,41 @@ +.prism-code .token { + white-space: pre; +} +.prism-code .string { + word-break: break-all; +} +.prism-code .class-name { + color: var(--purple-dark); +} +.prism-code .parameter, +.prism-code .plain, +.prism-code .property { + color: var(--gray-900); +} + +.prism-code .line-number { + padding: 0 16px; +} +.prism-code .line-number { + line-height: 2; + font-weight: 400; + color: var(--gray-500); + text-align: right; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.prism-code .line-content { + line-height: 1.72; + font-weight: 400; +} +.prism-code.language-json .token.property { + color: var(--blue-dark); +} +.prism-code.language-json .token.number { + color: var(--orange-dark); +} +.prism-code.language-bash { + padding: 0 24px; +} diff --git a/tools/devtools/src/devtools/panel/index.html b/tools/devtools/src/devtools/panel/index.html new file mode 100644 index 000000000..e52c2d863 --- /dev/null +++ b/tools/devtools/src/devtools/panel/index.html @@ -0,0 +1,13 @@ + + + + Yorkie Devtools + + + + + +
+ + + diff --git a/tools/devtools/src/devtools/panel/index.tsx b/tools/devtools/src/devtools/panel/index.tsx new file mode 100644 index 000000000..36008dcb8 --- /dev/null +++ b/tools/devtools/src/devtools/panel/index.tsx @@ -0,0 +1,72 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createRoot } from 'react-dom/client'; + +import { SeleteNodeProvider } from '../contexts/SeletedNode'; +import { SeletedPresenceProvider } from '../contexts/SeletedPresence'; +import { + YorkieSourceProvider, + useCurrentDocKey, +} from '../contexts/YorkieSource'; +import { Document } from '../tabs/Document'; +import { Presence } from '../tabs/Presence'; + +const Panel = () => { + const currentDocKey = useCurrentDocKey(); + + if (!currentDocKey) { + return ( +
+

Yorkie is not found in this page.

+

+ If this seems wrong, try reloading the page. +
Requires a development build of yorkie-js-sdk v0.4.13 or newer. +

+ +
+ ); + } + + return ( +
+ + + + + + +
+ ); +}; + +function PanelApp() { + return ( + + + + ); +} + +const root = createRoot(document.getElementById('root')); +root.render(); diff --git a/tools/devtools/src/devtools/panel/styles.css b/tools/devtools/src/devtools/panel/styles.css new file mode 100644 index 000000000..246a40b58 --- /dev/null +++ b/tools/devtools/src/devtools/panel/styles.css @@ -0,0 +1,337 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --gray-900: #332e2b; + --gray-800: #514c49; + --gray-700: #6e6966; + --gray-600: #807b78; + --gray-500: #a6a19e; + --gray-400: #c2bdba; + --gray-300: #e2dedb; + --gray-200: #efeceb; + --gray-100: #f5f3f1; + --gray-50: #faf8f6; + --gray-000: #fefdfb; + --orange-dark: #f27b2f; + --orange-0: #fc8539; + --orange-light: #fda36a; + --yellow-dark: #f5b103; + --yellow-0: #fdc433; + --yellow-light: #fed366; + --green-dark: #10b266; + --green-0: #23c176; + --green-light: #5ad198; + --blue-dark: #208aed; + --blue-0: #3c9af1; + --blue-light: #6db4f5; + --red-dark: #e93d47; + --red-0: #f44954; + --red-light: #f7777e; + --purple-dark: #764af3; + --purple-0: #855cf9; + --purple-light: #a385fb; +} + +.yorkie-devtools-empty { + display: flex; + flex-direction: column; + align-items: center; + padding-top: 30%; + height: 100vh; + color: var(--gray-900); + line-height: 1.4; +} + +.yorkie-devtools-empty .empty-title { + font-size: 1.4em; + font-weight: 500; + margin-bottom: 10px; +} + +.yorkie-devtools-empty .empty-desc { + color: var(--gray-600); +} + +.yorkie-devtools-empty .reload-btn { + margin-top: 20px; + padding: 6px 12px; + border: 1px solid var(--gray-300); + border-radius: 4px; + background: var(--gray-100); + color: var(--gray-600); + cursor: pointer; +} + +.yorkie-devtools-empty .reload-btn:hover { + background: var(--gray-200); +} + +.yorkie-devtools { + display: flex; + flex-direction: row; + width: 100%; + height: 100vh; +} + +.content-wrap { + display: flex; + flex-direction: column; + height: 100%; + padding: 6px 10px; +} + +.yorkie-root { + width: 60%; + border-right: 1px solid var(--gray-300); +} + +.yorkie-presence { + width: 40%; +} + +.content-wrap .title { + margin: 6px 0 14px; + font-weight: 500; +} + +.content-wrap .content { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; +} + +.arborist-tree-container { + flex: 1; + min-height: 0; + min-width: 0; +} + +.arborist-tree { + font-size: 11px; + font-family: menlo, monospace; + color: #444; + white-space: nowrap; +} + +.arborist-tree-row .tree-item { + display: inline-flex; + align-items: center; + position: relative; + margin-bottom: 16px; + padding: 6px 8px; + max-width: 100%; + border: 1px solid var(--gray-300); + border-radius: 4px; + cursor: pointer; +} + +.arborist-tree-row .tree-item:hover { + background: var(--gray-50); +} + +.arborist-tree-row .tree-item:after { + border: 1px dashed var(--gray-300); + border-radius: 0 0 0 4px; + border-width: 0 0 1px 1px; + content: ''; + position: absolute; + width: 16px; + height: 26px; + top: -14px; + left: -18px; +} + +.arborist-tree-row .tree-item:before { + border: 1px dashed var(--gray-300); + border-width: 0 0 0 1px; + content: ''; + position: absolute; + bottom: 0px; + left: -18px; + top: 12px; +} + +.arborist-tree-row .tree-item.last-child:before { + display: none; +} + +.arborist-tree .tree-item.is-selected { + background: var(--gray-100); +} + +.arborist-tree-row .tree-value { + overflow: hidden; + text-overflow: ellipsis; + color: var(--gray-600); +} + +.arborist-tree .timeticket { + margin-left: 6px; + padding: 2px 6px; + background: var(--gray-100); + border-radius: 4px; + font-size: 90%; +} + +.arborist-tree .icon { + margin-right: 6px; + height: 16px; +} +.arborist-tree .icon.object { + color: var(--yellow-light); +} +.arborist-tree .icon.array { + color: var(--green-light); +} +.arborist-tree .icon.primitive { + color: var(--gray-400); +} +.arborist-tree .icon.text { + color: var(--blue-light); +} +.arborist-tree .icon.tree { + color: var(--purple-light); +} +.arborist-tree .icon.counter { + color: var(--red-light); +} +.arborist-tree .icon.user { + color: var(--orange-light); +} +.arborist-tree .arrow-icon { + margin-right: 4px; +} + +.selected-content { + height: 66%; + border-top: 1px solid var(--gray-300); + display: flex; + flex-direction: column; +} + +.selected-view { + flex: 1; + min-height: 0; +} + +.selected-title { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.9em; + font-weight: 500; + padding: 6px 8px; + border-bottom: 1px solid var(--gray-300); + margin-bottom: 6px; +} + +.selected-close-btn { + border: none; + background: none; + width: 16px; + height: 16px; + color: var(--gray-300); + cursor: pointer; +} + +.selected-close-btn:hover { + color: var(--gray-500); +} + +.selected-view-tabmenu { + position: absolute; + right: 0; + display: flex; + margin-right: 14px; + border: 1px solid var(--gray-300); + border-radius: 4px; + overflow: hidden; +} + +.selected-view-btn { + display: flex; + align-items: center; + justify-content: center; + border: none; + border-right: 1px solid var(--gray-300); + background: none; + width: 20px; + height: 20px; + cursor: pointer; + color: var(--gray-300); +} + +.selected-view-btn:last-child { + border-right: none; +} + +.selected-view-btn:hover { + color: var(--gray-500); +} + +.selected-view-btn.is-selected { + background: var(--gray-300); + color: var(--gray-500); +} + +.selected-view-tab { + height: 100%; + position: relative; + overflow: scroll; + white-space: nowrap; +} + +.prism-code { + font-family: menlo, monospace; + font-size: 0.5em; + height: 100%; + overflow: auto; +} + +.tree-node { + margin-left: calc(16px * var(--depth)); + margin-bottom: 2px; + font-family: menlo, monospace; + color: #444; + font-size: 0.9em; +} + +.tree-node.text { + display: inline-block; +} + +.tree-node .node-item { + display: inline-flex; + flex-direction: column; + padding: 2px 4px; + border: 1px solid var(--gray-300); + border-radius: 4px; + cursor: pointer; +} + +.tree-node .node-item:hover { + background: var(--gray-300) !important; +} + +.tree-node.is-selected .node-item { + background: var(--gray-600) !important; + color: var(--gray-50); +} + +.tree-node.text .node-item { + background: var(--gray-100); +} + +.tree-node span { + padding: 2px; +} + +.tree-node .timeticket { + border-top: 1px solid var(--gray-300); + font-size: 9px; +} diff --git a/tools/devtools/src/devtools/tabs/Document.tsx b/tools/devtools/src/devtools/tabs/Document.tsx new file mode 100644 index 000000000..5fe45c108 --- /dev/null +++ b/tools/devtools/src/devtools/tabs/Document.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RootTree } from '../components/Tree'; +import { JSONDetail, TreeDetail } from '../components/Detail'; +import { useSeletedNode } from '../contexts/SeletedNode'; +import { + useCurrentDocKey, + useDocumentRoot, + useNodeDetail, +} from '../contexts/YorkieSource'; +import { CloseIcon } from '../icons'; + +export function Document() { + const currentDocKey = useCurrentDocKey(); + const root = useDocumentRoot(); + const nodeDetail = useNodeDetail(); + const [selectedNode, setSelectedNode] = useSeletedNode(); + + return ( +
+
{currentDocKey || 'Document'}
+
+ + {selectedNode && ( +
+
+ {selectedNode.id} + +
+
+ {selectedNode.type === 'YORKIE_TREE' ? ( + + ) : ( + + )} +
+
+ )} +
+
+ ); +} diff --git a/tools/devtools/src/devtools/tabs/Presence.tsx b/tools/devtools/src/devtools/tabs/Presence.tsx new file mode 100644 index 000000000..7a2dd601c --- /dev/null +++ b/tools/devtools/src/devtools/tabs/Presence.tsx @@ -0,0 +1,53 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { PresenceTree } from '../components/Tree'; +import { JSONDetail } from '../components/Detail'; +import { useSeletedPresence } from '../contexts/SeletedPresence'; +import { usePresences } from '../contexts/YorkieSource'; +import { CloseIcon } from '../icons'; + +export function Presence() { + const presences = usePresences(); + const [selectedPresence, setSelectedPresence] = useSeletedPresence(); + + return ( +
+
Presence
+
+ + {selectedPresence && ( +
+
+ {selectedPresence.key} + +
+ +
+ )} +
+
+ ); +} diff --git a/tools/devtools/src/popup/index.tsx b/tools/devtools/src/popup/index.tsx new file mode 100644 index 000000000..2859a24ae --- /dev/null +++ b/tools/devtools/src/popup/index.tsx @@ -0,0 +1,31 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function Popup() { + return ( +
+ Please open the developer tools, and "🐶 Yorkie" tab will be shown. +
+ ); +} + +export default Popup; diff --git a/tools/devtools/src/port.ts b/tools/devtools/src/port.ts new file mode 100644 index 000000000..f4c5b49bd --- /dev/null +++ b/tools/devtools/src/port.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { PanelToSDKMessage } from './protocol'; +import { EventSourceDevPanel } from './protocol'; + +const tabID = chrome.devtools.inspectedWindow.tabId; + +// `tabs.connect()` creates a reusable channel for long-term message passing between +// an extension page and a content script. This port can be used for communication with the +// inspected window of a Devtools extension. +// For more details: https://developer.chrome.com/docs/extensions/develop/concepts/messaging#connect +let port: chrome.runtime.Port; +port = chrome.tabs.connect(tabID, { + name: EventSourceDevPanel, +}); +port.onDisconnect.addListener(() => { + port = undefined; +}); + +export const sendToSDK = (message: PanelToSDKMessage) => { + if (!port) return; + port.postMessage({ + source: EventSourceDevPanel, + ...message, + }); +}; + +export const onPortMessage = port.onMessage; + +// TODO(chacha912): The inspected window was reloaded, so we should reload the panel. +// Ideally, we should reconnect instead of performing a full reload. +// TODO(hackerwins): We need to ensure that this event listener should be +// removed later. +chrome.tabs.onUpdated.addListener((id, { status }) => { + if (status === 'complete' && tabID === id) { + window.location.reload(); + } +}); diff --git a/tools/devtools/src/protocol.ts b/tools/devtools/src/protocol.ts new file mode 100644 index 000000000..b3bf85f91 --- /dev/null +++ b/tools/devtools/src/protocol.ts @@ -0,0 +1,193 @@ +/* + * Copyright 2024 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * TODO(chacha912): This code is a copy from src/devtools/protocol.ts. + * It is intended to be used by importing it from yorkie-js-sdk when + * it is structured as a monorepo. + */ +import type { DocEvent, PrimitiveValue } from 'yorkie-js-sdk'; + +/** + * `EventSourceDevPanel` is the name of the source representing messages + * from the Devtools panel. + */ +export const EventSourceDevPanel = 'yorkie-devtools-panel'; + +/** + * `EventSourceSDK` is the name of the source representing messages + * from the SDK. + */ +export const EventSourceSDK = 'yorkie-devtools-sdk'; + +/** + * Definition of all messages the Devtools panel can send to the SDK. + */ +export type PanelToSDKMessage = + /** + * Initial message from the panel to the SDK. It is sent when the panel is opened. + */ + | { msg: 'devtools::connect' } + /** + * Sent when the panel is not available. + */ + | { msg: 'devtools::disconnect' } + /** + * Informs the SDK that the panel is interested in receiving the "event" for the document, + * starting with the initial "full sync" event. + */ + | { + msg: 'devtools::subscribe'; + docKey: string; + } + /** + * Requests the detailed information for the node corresponding to the given path. + */ + | { + msg: 'devtools::node::detail'; + data: { + path: string; + type: string; + }; + }; + +/** + * Definition of all messages the SDK can send to the Devtools panel. + */ +export type SDKToPanelMessage = + /** + * Sent when the document is available for the panel to watch. + */ + | { + msg: 'doc::available'; + docKey: string; + } + /** + * Sent initially, to synchronize the entire current state of the document. + */ + | { + msg: 'doc::sync::full'; + docKey: string; + root: JSONElement; + clients: Array; + } + /** + * Sent whenever the document is updated. + */ + | { + msg: 'doc::sync::partial'; + docKey: string; + event?: DocEvent; + root?: JSONElement; + clients?: Array; + } + /** + * Sent detailed information for the node corresponding to the given path. + */ + | { + msg: 'doc::node::detail'; + node: TreeNodeInfo; + }; + +export type FullPanelToSDKMessage = PanelToSDKMessage & { + source: 'yorkie-devtools-panel'; +}; + +export type FullSDKToPanelMessage = SDKToPanelMessage & { + source: 'yorkie-devtools-sdk'; +}; + +/** + * TODO(chacha912): This code is a copy from src/types/devtools.ts. + * It is intended to be used by importing it from yorkie-js-sdk when + * it is structured as a monorepo. + */ + +/** + * `Json` represents a JSON value. + * + * TODO(hackerwins): We need to replace `Indexable` with `Json`. + */ +export type Json = + | string + | number + | boolean + // eslint-disable-next-line @typescript-eslint/ban-types + | null + | { [key: string]: Json } + | Array; + +/** + * `Client` represents a client value in devtools. + */ +export type Client = { + clientID: string; + presence: Json; +}; + +/** + * `JSONElement` represents the result of `Element.toJSForTest()`. + */ +export type JSONElement = { + type: JSONElementType; + key?: string; + value: JSONElementValue; + createdAt: string; +}; + +type JSONElementType = + | 'YORKIE_PRIMITIVE' + | 'YORKIE_COUNTER' + | 'YORKIE_OBJECT' + | 'YORKIE_ARRAY' + | 'YORKIE_TEXT' + | 'YORKIE_TREE'; + +/** + * `ElementValue` represents the result of `Element.toJSForTest()`. + * + * NOTE(chacha912): Json type is used to represent the result of + * `Text.toJSForTest()` and `Tree.toJSForTest()`. + */ +type JSONElementValue = + | PrimitiveValue + | ContainerValue // Array | Object + | Json; // Text | Tree + +/** + * `ContainerValue` represents the result of `Array.toJSForTest()` and + * `Object.toJSForTest()`. + */ +export type ContainerValue = { + [key: string]: JSONElement; +}; + +/** + * `TreeNodeInfo` represents the tree node information in devtools. + */ +export type TreeNodeInfo = { + id: string; + type: string; + parent?: string; + size: number; + value?: string; + removedAt?: string; + isRemoved: boolean; + insPrev?: string; + insNext?: string; + children: Array; + depth: number; +}; diff --git a/tools/devtools/tsconfig.json b/tools/devtools/tsconfig.json new file mode 100644 index 000000000..9c10ec491 --- /dev/null +++ b/tools/devtools/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "plasmo/templates/tsconfig.base", + "exclude": [ + "node_modules" + ], + "include": [ + ".plasmo/index.d.ts", + "./**/*.ts", + "./**/*.tsx" + ], + "compilerOptions": { + "paths": { + "~*": [ + "./*" + ] + }, + "baseUrl": "." + } +} diff --git a/vitest.config.ts b/vitest.config.ts index 8d377eefe..2a67e8dbc 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,7 +7,7 @@ const isCI = process.env.CI === 'true'; export default defineConfig({ test: { include: ['**/*_{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - exclude: ['**/bench/*'], + exclude: ['**/bench/*', '**/node_modules/**'], coverage: { provider: 'istanbul', reporter: ['lcov', 'text-summary'], From 80f933a4bbeb41775280313dee5e0a12b546ac4e Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Fri, 19 Jan 2024 11:56:25 +0900 Subject: [PATCH 33/48] Update CHANGELOG.md for v0.4.13-rc2 (#727) --- CHANGELOG.md | 352 ++++++++++++++++++++++++++----------------- package.json | 2 +- package.publish.json | 6 +- 3 files changed, 217 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91240dbcc..ef28de5c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,263 +7,315 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +### Added + +- Implement devtools chrome extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/717 + +### Changed + +- Complement concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/721 + ### Fixed -* Fix invalid tree conversion by @hackerwins, @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/719 + +- Fix invalid tree conversion by @hackerwins, @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/719 ## [0.4.12] - 2024-01-05 ### Added -* Add concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/710 + +- Add concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/710 ### Fixed -* Generate correct TreeChange in concurrent edits by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/712 -* Add forced sync when switching to realtime mode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/713 -* Fix `getGarbageLen` to retrun correct size by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/714 -* Prevent deregisterElement from deregistering twice in nested object by @justiceHui in https://github.com/yorkie-team/yorkie-js-sdk/pull/716 + +- Generate correct TreeChange in concurrent edits by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/712 +- Add forced sync when switching to realtime mode by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/713 +- Fix `getGarbageLen` to retrun correct size by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/714 +- Prevent deregisterElement from deregistering twice in nested object by @justiceHui in https://github.com/yorkie-team/yorkie-js-sdk/pull/716 ## [0.4.11] - 2023-12-18 ### Added -* Address duplicate node IDs in Tree.Split by @sejongk, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/707 -* Add test filtering and log printing guide to CONTRIBUTING.md by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/708 -* Support concurrent insertion and splitting in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/709 + +- Address duplicate node IDs in Tree.Split by @sejongk, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/707 +- Add test filtering and log printing guide to CONTRIBUTING.md by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/708 +- Support concurrent insertion and splitting in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/709 ### Changed -* Migrate RPC to ConnectRPC by @krapie, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/698 + +- Migrate RPC to ConnectRPC by @krapie, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/698 ## [0.4.10] - 2023-12-04 ### Added -* Add create-yorkie-app by @se030, @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/690 -* Implement splitLevel of Tree.Edit by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/704 -* Add `removeIfNotAttached` to `client.detach()` options by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/703 +- Add create-yorkie-app by @se030, @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/690 +- Implement splitLevel of Tree.Edit by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/704 +- Add `removeIfNotAttached` to `client.detach()` options by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/703 ### Fixed -* Fix reading wrong .env path by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/694 -* Handle escape string for strings containing quotes by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/700 -* Correct typos in the installation command on README.md in the example by @ymw0407 in https://github.com/yorkie-team/yorkie-js-sdk/pull/702 + +- Fix reading wrong .env path by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/694 +- Handle escape string for strings containing quotes by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/700 +- Correct typos in the installation command on README.md in the example by @ymw0407 in https://github.com/yorkie-team/yorkie-js-sdk/pull/702 ## [0.4.9] - 2023-11-25 ### Added -* Implement merge elements in `Tree.Edit` by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/681 -* Add README and thumbnail on example 'simultaneous-cursors'by @banma1234 in https://github.com/yorkie-team/yorkie-js-sdk/pull/683 -* Support Undo/Redo for object.set and object.remove operations by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/658 + +- Implement merge elements in `Tree.Edit` by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/681 +- Add README and thumbnail on example 'simultaneous-cursors'by @banma1234 in https://github.com/yorkie-team/yorkie-js-sdk/pull/683 +- Support Undo/Redo for object.set and object.remove operations by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/658 ### Changed -* Refactor ProseMirror example and Tree codes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/686 -* Enhance Set and Add for representing nested elements by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/691 + +- Refactor ProseMirror example and Tree codes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/686 +- Enhance Set and Add for representing nested elements by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/691 ### Fixed -* Add missing `removedAt` during Primitive deepcopy by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/692 -* Prevent empty ops are applied during undo/redo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/687 + +- Add missing `removedAt` during Primitive deepcopy by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/692 +- Prevent empty ops are applied during undo/redo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/687 ## [0.4.8] - 2023-11-01 ### Changed -* Replace karma with vitest by @blurfx, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/665 -* Remove vitest single thread config by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/667 -* Publish npm package with provenance by @jongwooo in https://github.com/yorkie-team/yorkie-js-sdk/pull/669 -* Update examples version to v0.4.7 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/671 -* Update nextjs-scheduler to export static files by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/672 -* Bump browserify-sign from 4.2.1 to 4.2.2 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/678 -* Bump @babel/traverse from 7.22.11 to 7.23.2 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/670 + +- Replace karma with vitest by @blurfx, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/665 +- Remove vitest single thread config by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/667 +- Publish npm package with provenance by @jongwooo in https://github.com/yorkie-team/yorkie-js-sdk/pull/669 +- Update examples version to v0.4.7 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/671 +- Update nextjs-scheduler to export static files by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/672 +- Bump browserify-sign from 4.2.1 to 4.2.2 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/678 +- Bump @babel/traverse from 7.22.11 to 7.23.2 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/670 ### Removed -* Remove redundant types from tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/666 + +- Remove redundant types from tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/666 ### Fixed -* Fix missing collection of removed elements from the root by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/676 -* Add more GC tests to reflect current server modifications by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/677 -* Fit Next.js example style to the yorkie homepage by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/675 -* Disable jekyll on github actions by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/674 + +- Fix missing collection of removed elements from the root by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/676 +- Add more GC tests to reflect current server modifications by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/677 +- Fit Next.js example style to the yorkie homepage by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/675 +- Disable jekyll on github actions by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/674 ## [0.4.7] - 2023-10-06 ### Added -* Introduce basic architecture to support undo and redo by @hyemmie, @chacha912 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/650 -* Add Text devtool to CodeMirror example by @chacha912 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/646 -* Add DisableGC option to document by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/644 -* Add toJS to return TreeNode of Tree by @JOOHOJANG and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/639 -* Add Tree.Edit benchmark and improve performance by @JOOHOJANG and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/641 -* Add simultaneous cursors example and Update examples to v0.4.6 by @YoonKiJin and @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/581 -* Add nextjs-scheduler example by @banma1234 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/637 + +- Introduce basic architecture to support undo and redo by @hyemmie, @chacha912 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/650 +- Add Text devtool to CodeMirror example by @chacha912 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/646 +- Add DisableGC option to document by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/644 +- Add toJS to return TreeNode of Tree by @JOOHOJANG and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/639 +- Add Tree.Edit benchmark and improve performance by @JOOHOJANG and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/641 +- Add simultaneous cursors example and Update examples to v0.4.6 by @YoonKiJin and @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/581 +- Add nextjs-scheduler example by @banma1234 and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/637 ### Changed -* Improve tldraw example performance by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/640 -* Drop node 16 support by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/653 -* Strip internals from package d.ts files by @mojosoeun in https://github.com/yorkie-team/yorkie-js-sdk/pull/596 -* Disable realtime sync in GC test (#656) by @sejongk and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/656 + +- Improve tldraw example performance by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/640 +- Drop node 16 support by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/653 +- Strip internals from package d.ts files by @mojosoeun in https://github.com/yorkie-team/yorkie-js-sdk/pull/596 +- Disable realtime sync in GC test (#656) by @sejongk and @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/656 ### Removed -* Remove unused trie by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/651 -* Remove SelectOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/636 + +- Remove unused trie by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/651 +- Remove SelectOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/636 ### Fixed -* Support concurrent formatting of Text by @MoonGyu1 in https://github.com/yorkie-team/yorkie-js-sdk/pull/642 -* Recover istanbul-instrumenter-loader to use debugger by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/659 -* Recover Select to prevent unsupported operation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/634 + +- Support concurrent formatting of Text by @MoonGyu1 in https://github.com/yorkie-team/yorkie-js-sdk/pull/642 +- Recover istanbul-instrumenter-loader to use debugger by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/659 +- Recover Select to prevent unsupported operation by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/634 ## [0.4.6] - 2023-08-25 ### Added -* Build error on node 18+ by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/584 -* Add .nvmrc to specify Node version to LTS by @kutta97 in https://github.com/yorkie-team/yorkie-js-sdk/pull/586 -* Add client deactivation before unmount by @degurii in https://github.com/yorkie-team/yorkie-js-sdk/pull/595 -* Add `presence.get()` to get presence value in doc.update() by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/600 -* Add test for concurrent rich-text editing in the Peritext example by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/610 -* Concurrent case handling for Yorkie.tree by @ehuas in https://github.com/yorkie-team/yorkie-js-sdk/pull/611 -* Support multi-level and parital element selection by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/631 - -### Changed -* Move "Building & Testing" Guide to CONTRIBUTING.md by @g2hhh2ee in https://github.com/yorkie-team/yorkie-js-sdk/pull/589 -* Define more specific condition to check whether the input is opened by @su-ram in https://github.com/yorkie-team/yorkie-js-sdk/pull/597 -* Clean up methods related to presence by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/599 -* Refactor presence event code in examples by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/614 -* Change TreeNode to have IDs instead of insPrev, insNext by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/627 -* Remove select operation from text by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/622 -* Fix invalid path of style changes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/632 + +- Build error on node 18+ by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/584 +- Add .nvmrc to specify Node version to LTS by @kutta97 in https://github.com/yorkie-team/yorkie-js-sdk/pull/586 +- Add client deactivation before unmount by @degurii in https://github.com/yorkie-team/yorkie-js-sdk/pull/595 +- Add `presence.get()` to get presence value in doc.update() by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/600 +- Add test for concurrent rich-text editing in the Peritext example by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/610 +- Concurrent case handling for Yorkie.tree by @ehuas in https://github.com/yorkie-team/yorkie-js-sdk/pull/611 +- Support multi-level and parital element selection by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/631 + +### Changed + +- Move "Building & Testing" Guide to CONTRIBUTING.md by @g2hhh2ee in https://github.com/yorkie-team/yorkie-js-sdk/pull/589 +- Define more specific condition to check whether the input is opened by @su-ram in https://github.com/yorkie-team/yorkie-js-sdk/pull/597 +- Clean up methods related to presence by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/599 +- Refactor presence event code in examples by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/614 +- Change TreeNode to have IDs instead of insPrev, insNext by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/627 +- Remove select operation from text by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/622 +- Fix invalid path of style changes by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/632 ### Removed ### Fixed -* Fix `pathToTreePos` TC by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/571 -* Fix GC to remove all removed nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/568 -* Expose pathToIndex API by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/567 -* Fix react-tldraw readme typo by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/598 -* Fix event-related tests to be deterministic by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/602 -* Fix high and critical vulnerabilities by @mojosoeun in https://github.com/yorkie-team/yorkie-js-sdk/pull/630 + +- Fix `pathToTreePos` TC by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/571 +- Fix GC to remove all removed nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/568 +- Expose pathToIndex API by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/567 +- Fix react-tldraw readme typo by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/598 +- Fix event-related tests to be deterministic by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/602 +- Fix high and critical vulnerabilities by @mojosoeun in https://github.com/yorkie-team/yorkie-js-sdk/pull/630 ## [0.4.5] - 2023-07-20 ### Added -* Move Presence from Client to Document by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/574 -* Tree edit update by @ehuas in https://github.com/yorkie-team/yorkie-js-sdk/pull/576 + +- Move Presence from Client to Document by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/574 +- Tree edit update by @ehuas in https://github.com/yorkie-team/yorkie-js-sdk/pull/576 ### Changed -* Replace selection with presence by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/578 -* Bump word-wrap from 1.2.3 to 1.2.4 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/575 -* Bump up protobuf by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/570 -* Prevent usage of `.` in JSONObject key by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/569 + +- Replace selection with presence by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/578 +- Bump word-wrap from 1.2.3 to 1.2.4 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/575 +- Bump up protobuf by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/570 +- Prevent usage of `.` in JSONObject key by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/569 ### Removed -* Remove duplicated test by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/564 -* Remove InternalOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/566 + +- Remove duplicated test by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/564 +- Remove InternalOpInfo by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/566 ### Fixed -* Fix `pathToTreePos` TC by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/571 -* Fix GC to remove all removed nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/568 -* Expose pathToIndex API by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/567 + +- Fix `pathToTreePos` TC by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/571 +- Fix GC to remove all removed nodes by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/568 +- Expose pathToIndex API by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/567 ## [0.4.4] - 2023-07-05 ### Changed -* Cleanup of test-related terminology by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/562 -* Use TreeRangeStruct to represent tree selection by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/561 + +- Cleanup of test-related terminology by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/562 +- Use TreeRangeStruct to represent tree selection by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/561 ## [0.4.3] - 2023-06-29 ### Added -* Apply garbage collection to tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/550 + +- Apply garbage collection to tree by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/550 ### Changed -* Cleanup TextChange by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/551 + +- Cleanup TextChange by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/551 ### Fixed -* Fix garbage collection bug by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/555 + +- Fix garbage collection bug by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/555 ## [0.4.2] - 2023-06-19 ### Added -* Support for OperationInfo inference on Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/535 -* Add peer selection display example by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/544 -* Implement Tree.Style and Tree.StyleByPath by @JOOHOJANG, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/542 + +- Support for OperationInfo inference on Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/535 +- Add peer selection display example by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/544 +- Implement Tree.Style and Tree.StyleByPath by @JOOHOJANG, @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/542 ## [0.4.1] - 2023-06-09 ### Changed -* Bump vite from 3.2.5 to 3.2.7 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/531 -* change to next method as synchronously by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/526 -* Change the value of XXXChange to Change in Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/538 -* Replace Tree.onChanges with Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/523 + +- Bump vite from 3.2.5 to 3.2.7 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/531 +- change to next method as synchronously by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/526 +- Change the value of XXXChange to Change in Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/538 +- Replace Tree.onChanges with Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/523 ## [0.4.0] - 2023-06-05 ### Added -* Implement yorkie.Tree for text editors using tree model by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/507 + +- Implement yorkie.Tree for text editors using tree model by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/507 ### Changed -* Bump socket.io-parser from 4.2.1 to 4.2.3 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/516 -* Replace Text.onChanges with Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/519 + +- Bump socket.io-parser from 4.2.1 to 4.2.3 by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/516 +- Replace Text.onChanges with Document.subscribe by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/519 ## [0.3.5] - 2023-05-22 ### Changed -* Bump yaml and husky by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/505 -* Apply Integration of SDK and Admin RPC Server by @krapie in https://github.com/yorkie-team/yorkie-js-sdk/pull/512 + +- Bump yaml and husky by @dependabot in https://github.com/yorkie-team/yorkie-js-sdk/pull/505 +- Apply Integration of SDK and Admin RPC Server by @krapie in https://github.com/yorkie-team/yorkie-js-sdk/pull/512 ### Fixed -* Fix quill example page image rendering issue by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/504 -* Add actor to ChangeInfo / update api-reference by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/508 + +- Fix quill example page image rendering issue by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/504 +- Add actor to ChangeInfo / update api-reference by @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/508 ## [0.3.4] - 2023-04-18 ### Added -* Add the `document.subscribe(targetPath, (event) => {})`, which enables users to subscribe to a specific target in a document by @chacha912 in #487 -* Add the `document.getValueByPath()` to get the value of a document by specifying the path by @chacha912 in #487 -* Add benchmark tests for yorkie.Document by @JOOHOJANG in #494 -* Add client sync mode, which enables users to pause and resume remote changes by @chacha912 in #495 -* Add x-shard-key to APIs by @hackerwins in #486 -* Add yorkie user agent in grpc metadata by @emplam27 in #488 + +- Add the `document.subscribe(targetPath, (event) => {})`, which enables users to subscribe to a specific target in a document by @chacha912 in #487 +- Add the `document.getValueByPath()` to get the value of a document by specifying the path by @chacha912 in #487 +- Add benchmark tests for yorkie.Document by @JOOHOJANG in #494 +- Add client sync mode, which enables users to pause and resume remote changes by @chacha912 in #495 +- Add x-shard-key to APIs by @hackerwins in #486 +- Add yorkie user agent in grpc metadata by @emplam27 in #488 ### Changed -* Change Counter.increase() to remove the decimal part instead of using Math.floor() when a decimal number is passed as an argument by @JOOHOJANG in #496 + +- Change Counter.increase() to remove the decimal part instead of using Math.floor() when a decimal number is passed as an argument by @JOOHOJANG in #496 ### Fixed -* Return undefined when searching for presence of non-existent peer by @chacha912 in #493 + +- Return undefined when searching for presence of non-existent peer by @chacha912 in #493 ## [0.3.3] - 2023-03-24 ### Added -* Add optimization option in production mode by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/474 -* Add RemoveDocument API by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/480 -* Add pause and resume to Client by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/482 + +- Add optimization option in production mode by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/474 +- Add RemoveDocument API by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/480 +- Add pause and resume to Client by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/482 ### Changed -* Clarify the ClientEvent that is sent to client.subscribe by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/464 -* Rename initialization to initialized in PeersChangedEvent by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/478 + +- Clarify the ClientEvent that is sent to client.subscribe by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/464 +- Rename initialization to initialized in PeersChangedEvent by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/478 ### Fixed ## [0.3.2] - 2023-02-27 ### Fixed -* Fix ValueChange dependency by @krapie in https://github.com/yorkie-team/yorkie-js-sdk/pull/470 + +- Fix ValueChange dependency by @krapie in https://github.com/yorkie-team/yorkie-js-sdk/pull/470 ## [0.3.1] - 2023-02-27 ### Added -* Add `delete` and `empty` method to `Text` data type by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/454 + +- Add `delete` and `empty` method to `Text` data type by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/454 ### Changed -* Reduce bundle size for production by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/460 -* Remove string dependency of RGATreeSplit value by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/459 -* Remove priority queue from RHTPQMap and entire project by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/462 -* Modify config to run the webpack-bundle-analyzer when using `profile:bundle` script by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/468 + +- Reduce bundle size for production by @easylogic in https://github.com/yorkie-team/yorkie-js-sdk/pull/460 +- Remove string dependency of RGATreeSplit value by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/459 +- Remove priority queue from RHTPQMap and entire project by @blurfx in https://github.com/yorkie-team/yorkie-js-sdk/pull/462 +- Modify config to run the webpack-bundle-analyzer when using `profile:bundle` script by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/468 ### Fixed -* Fix invalid indexOf SplayTree with single node by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/463 + +- Fix invalid indexOf SplayTree with single node by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/463 ## [0.3.0] - 2023-01-31 ### Changed + - Merge Text and RichText by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/425 - Fix the value type of Counter and remove double type from Counter by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/426 - Let Client.attach wait until stream initialization is finished by @cozitive in https://github.com/yorkie-team/yorkie-js-sdk/pull/440 - Add the toJS method to the ObjectProxy's handler by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/449 ### Fixed + - Increase CRDT Counter in local change by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/441 ## [0.2.20] - 2022-12-30 @@ -452,57 +504,70 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [0.1.11] - 2021-12-04 ### Fixed + - Fix a bug where text nodes with tombstones were not counted: #263 ## [0.1.10] - 2021-11-16 ### Added + - Add Array.toJS() and Object.toJS(): #237 ### Changed + - Print log message more accurately: #5ce95c6, #de05448 ### Fixed + - Fix quill example page: #260 ## [0.1.8] - 2021-10-21 ### Fixed + - Hide clock from value of peers-changed event ## [0.1.7] - 2021-10-19 ### Added + - Improve Client's metadata to be updatable: #240 ### Fixed + - Fix reduce array size when deleting the same position: #229 - Handle special characters in keys of the path in change events: #247 ## [0.1.6] - 2021-07-24 ### Added + - Add client.getStatus and client.Metadata: #162f2d5 ### Changed + - Change getElementByID to return undefined if the element doesnt exist: #208 - Change esnext to ES2019 in compiler target option: #197 - Clean up JS SDK Reference: #181, #218, #219 ### Fixed + - Fix a bug where deleted values from objects are revivded after GC: #216 ## [0.1.5] - 2021-06-05 ### Added + - Add moveFront, moveAfter, moveLast, insertBefore to Array: #194, #203, #206, #207 - Add AuthInterceptor: #199 ### Fixed + - Fix the concurrent editing issue of Move Operation: #196 - Fix a bug when pushing an array element in Array: #200 ### Removed + - Delete RequestHeader in Protobuf ## [0.1.4] - 2021-05-15 @@ -510,11 +575,13 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ### Added ### Changed + - Rename Document.getKey().toIDString() to Document.getKey(): #178 - Only display exported objects in JS SDK Reference: #179 - Rename Document to DocumentReplica: #10f2b72 ### Fixed + - Fix a bug occurs when setting an empty string as a key: #182 - Fix a bug that the first element of an array was not deleted: #185 - Fix a bug that the size of the array increases when moving element: #186 @@ -523,15 +590,18 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [0.1.3] - 2021-04-04 ### Added + - Pass paths to change events: #162 - Support null and undefined values: #157 - Add type parameter to Document: #148 ### Changed + - Rename getRootObject to getRoot: #158 - Rename updateSelection to select: #170 ### Fixed + - Fix error that occurred when deleting value using missing key or index: #149 - Fix invalid states of SplayTree: #153 - Remove errors that occur when insPrev does not exist: #166 @@ -539,46 +609,52 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [0.1.2] - 2021-02-14 ### Added + - Add customizable metadata for peer awareness: #123 - Add garbage collection for Text and RichText: #137 ### Changed + - Replace the type of client_id to a byte array to reduce payload: #133 ### Fixed + - Fix a bug that attributes were lost when splitting RichText nodes: #136 ## [0.1.1] - 2021-01-01 ### Added - - Add garbage collect for Container type: #101 + +- Add garbage collect for Container type: #101 ### Changed - - Update libs to fix security vulnerability: #103 + +- Update libs to fix security vulnerability: #103 ### Fixed - - Fix quill paragraph style errors: #104 - - Change Logger to receive all values: #100 + +- Fix quill paragraph style errors: #104 +- Change Logger to receive all values: #100 ## [0.1.0] - 2020-11-07 First public release ### Added - - Add `Client` and `Document` - - Add Custom CRDT data type `Text` for code editor - - Add Custom CRDT data type `RichText` for WYSIWYG editor - - Add examples: CodeMirror, Drawing, Quill - - Support Network Auto Recovery - - Add Peer Awareness - - Add Custom CRDT data type `Counter` + +- Add `Client` and `Document` +- Add Custom CRDT data type `Text` for code editor +- Add Custom CRDT data type `RichText` for WYSIWYG editor +- Add examples: CodeMirror, Drawing, Quill +- Support Network Auto Recovery +- Add Peer Awareness +- Add Custom CRDT data type `Counter` ### Changed ### Removed - -### Deprecated -[Unreleased]: https://github.com/yorkie-team/yorkie-js-sdk/compare/v0.1.0...HEAD -[0.1.0]: https://github.com/yorkie-team/yorkie-js-sdk/releases/tag/v0.1.0# +### Deprecated +[unreleased]: https://github.com/yorkie-team/yorkie-js-sdk/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/yorkie-team/yorkie-js-sdk/releases/tag/v0.1.0# diff --git a/package.json b/package.json index 8c4117d2f..4d1d0ba0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13-rc", + "version": "0.4.13-rc2", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index 291f0dffe..5a57119d6 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,12 +1,10 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13-rc", + "version": "0.4.13-rc2", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", - "files": [ - "dist" - ], + "files": ["dist"], "repository": { "type": "git", "url": "git+https://github.com/yorkie-team/yorkie-js-sdk.git" From d99680b23e72ba4eab8c634f77f2e4780c7364c1 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Fri, 19 Jan 2024 14:07:19 +0900 Subject: [PATCH 34/48] Fix multiple versions of prosemirror-model were loaded (#728) Related to https://github.com/ueberdosis/tiptap/issues/577 --- public/prosemirror.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/prosemirror.html b/public/prosemirror.html index 62380ed4a..e95295c3a 100644 --- a/public/prosemirror.html +++ b/public/prosemirror.html @@ -42,7 +42,7 @@

Yorkie.Tree

"imports": { "prosemirror-state": "https://cdn.jsdelivr.net/npm/prosemirror-state@1.4.3/+esm", "prosemirror-view": "https://cdn.jsdelivr.net/npm/prosemirror-view@1.31.4/+esm", - "prosemirror-model": "https://cdn.jsdelivr.net/npm/prosemirror-model@1.19.3/+esm", + "prosemirror-model": "https://cdn.jsdelivr.net/npm/prosemirror-model@1.19.4/+esm", "prosemirror-transform": "https://cdn.jsdelivr.net//npm/prosemirror-transform@1.7.3/+esm", "prosemirror-keymap": "https://cdn.jsdelivr.net/npm/prosemirror-keymap@1.2.2/+esm", "prosemirror-example-setup": "https://cdn.jsdelivr.net/npm/prosemirror-example-setup@1.2.2/+esm", From 383abd930ca3b6d36a20e8fe33d56ad770ba9555 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:26:09 +0900 Subject: [PATCH 35/48] Export devtools type (#730) --- src/yorkie.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/yorkie.ts b/src/yorkie.ts index 5198daefd..0730b48f1 100644 --- a/src/yorkie.ts +++ b/src/yorkie.ts @@ -20,6 +20,7 @@ import { Text } from '@yorkie-js-sdk/src/document/json/text'; import { Tree } from '@yorkie-js-sdk/src/document/json/tree'; import { Counter } from '@yorkie-js-sdk/src/document/json/counter'; import { CounterType } from '@yorkie-js-sdk/src/document/crdt/counter'; +import type * as Devtools from '@yorkie-js-sdk/src/devtools/types'; export { Client, @@ -106,6 +107,16 @@ export { export { Change } from '@yorkie-js-sdk/src/document/change/change'; export { converter } from '@yorkie-js-sdk/src/api/converter'; +export { + EventSourceDevPanel, + EventSourceSDK, + PanelToSDKMessage, + SDKToPanelMessage, + FullPanelToSDKMessage, + FullSDKToPanelMessage, +} from '@yorkie-js-sdk/src/devtools/protocol'; +export type { Devtools }; + /** * The top-level yorkie namespace with additional properties. * From 363229bfe2230d55c8d2326cda76e46deede3cc2 Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:15:09 +0900 Subject: [PATCH 36/48] Reflect interface changes of server DB sharding (#726) This commit reflects passing sharding keys to the SDK in advance before releasing the server with MongoDB sharding applied. --- src/api/yorkie/v1/yorkie.proto | 9 +++++++ src/api/yorkie/v1/yorkie_pb.d.ts | 45 +++++++++++++++++++++++++++++++ src/api/yorkie/v1/yorkie_pb.js | 9 +++++++ src/client/client.ts | 7 +++++ test/integration/document_test.ts | 15 ++++++++--- 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/api/yorkie/v1/yorkie.proto b/src/api/yorkie/v1/yorkie.proto index 279f96f98..0d4736778 100644 --- a/src/api/yorkie/v1/yorkie.proto +++ b/src/api/yorkie/v1/yorkie.proto @@ -48,6 +48,7 @@ message ActivateClientResponse { } message DeactivateClientRequest { + string client_key = 2; string client_id = 1; } @@ -55,6 +56,7 @@ message DeactivateClientResponse { } message AttachDocumentRequest { + string client_key = 3; string client_id = 1; ChangePack change_pack = 2; } @@ -65,6 +67,7 @@ message AttachDocumentResponse { } message DetachDocumentRequest { + string client_key = 5; string client_id = 1; string document_id = 2; ChangePack change_pack = 3; @@ -76,7 +79,9 @@ message DetachDocumentResponse { } message WatchDocumentRequest { + string client_key = 4; string client_id = 1; + string document_key = 3; string document_id = 2; } @@ -92,6 +97,7 @@ message WatchDocumentResponse { } message RemoveDocumentRequest { + string client_key = 4; string client_id = 1; string document_id = 2; ChangePack change_pack = 3; @@ -102,6 +108,7 @@ message RemoveDocumentResponse { } message PushPullChangesRequest { + string client_key = 5; string client_id = 1; string document_id = 2; ChangePack change_pack = 3; @@ -113,7 +120,9 @@ message PushPullChangesResponse { } message BroadcastRequest { + string client_key = 6; string client_id = 1; + string document_key = 5; string document_id = 2; string topic = 3; bytes payload = 4; diff --git a/src/api/yorkie/v1/yorkie_pb.d.ts b/src/api/yorkie/v1/yorkie_pb.d.ts index 0c685f6ad..18552637f 100644 --- a/src/api/yorkie/v1/yorkie_pb.d.ts +++ b/src/api/yorkie/v1/yorkie_pb.d.ts @@ -74,6 +74,11 @@ export declare class ActivateClientResponse extends Message { + /** + * @generated from field: string client_key = 2; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ @@ -117,6 +122,11 @@ export declare class DeactivateClientResponse extends Message { + /** + * @generated from field: string client_key = 3; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ @@ -175,6 +185,11 @@ export declare class AttachDocumentResponse extends Message { + /** + * @generated from field: string client_key = 5; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ @@ -238,11 +253,21 @@ export declare class DetachDocumentResponse extends Message { + /** + * @generated from field: string client_key = 4; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ clientId: string; + /** + * @generated from field: string document_key = 3; + */ + documentKey: string; + /** * @generated from field: string document_id = 2; */ @@ -327,6 +352,11 @@ export declare class WatchDocumentResponse_Initialization extends Message { + /** + * @generated from field: string client_key = 4; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ @@ -385,6 +415,11 @@ export declare class RemoveDocumentResponse extends Message { + /** + * @generated from field: string client_key = 5; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ @@ -448,11 +483,21 @@ export declare class PushPullChangesResponse extends Message { + /** + * @generated from field: string client_key = 6; + */ + clientKey: string; + /** * @generated from field: string client_id = 1; */ clientId: string; + /** + * @generated from field: string document_key = 5; + */ + documentKey: string; + /** * @generated from field: string document_id = 2; */ diff --git a/src/api/yorkie/v1/yorkie_pb.js b/src/api/yorkie/v1/yorkie_pb.js index 97b8ad6e8..2e00b36b5 100644 --- a/src/api/yorkie/v1/yorkie_pb.js +++ b/src/api/yorkie/v1/yorkie_pb.js @@ -50,6 +50,7 @@ const ActivateClientResponse = proto3.makeMessageType( const DeactivateClientRequest = proto3.makeMessageType( "yorkie.v1.DeactivateClientRequest", () => [ + { no: 2, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ], ); @@ -68,6 +69,7 @@ const DeactivateClientResponse = proto3.makeMessageType( const AttachDocumentRequest = proto3.makeMessageType( "yorkie.v1.AttachDocumentRequest", () => [ + { no: 3, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "change_pack", kind: "message", T: ChangePack }, ], @@ -90,6 +92,7 @@ const AttachDocumentResponse = proto3.makeMessageType( const DetachDocumentRequest = proto3.makeMessageType( "yorkie.v1.DetachDocumentRequest", () => [ + { no: 5, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "change_pack", kind: "message", T: ChangePack }, @@ -113,7 +116,9 @@ const DetachDocumentResponse = proto3.makeMessageType( const WatchDocumentRequest = proto3.makeMessageType( "yorkie.v1.WatchDocumentRequest", () => [ + { no: 4, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "document_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ], ); @@ -146,6 +151,7 @@ const WatchDocumentResponse_Initialization = proto3.makeMessageType( const RemoveDocumentRequest = proto3.makeMessageType( "yorkie.v1.RemoveDocumentRequest", () => [ + { no: 4, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "change_pack", kind: "message", T: ChangePack }, @@ -168,6 +174,7 @@ const RemoveDocumentResponse = proto3.makeMessageType( const PushPullChangesRequest = proto3.makeMessageType( "yorkie.v1.PushPullChangesRequest", () => [ + { no: 5, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "change_pack", kind: "message", T: ChangePack }, @@ -191,7 +198,9 @@ const PushPullChangesResponse = proto3.makeMessageType( const BroadcastRequest = proto3.makeMessageType( "yorkie.v1.BroadcastRequest", () => [ + { no: 6, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 5, name: "document_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 4, name: "payload", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, diff --git a/src/client/client.ts b/src/client/client.ts index b29b64d20..3ad744e5c 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -388,6 +388,7 @@ export class Client implements Observable { return this.rpcClient .deactivateClient( { + clientKey: this.key!, clientId: this.id!, }, { headers: { 'x-shard-key': this.apiKey } }, @@ -435,6 +436,7 @@ export class Client implements Observable { return this.rpcClient .attachDocument( { + clientKey: this.key!, clientId: this.id!, changePack: converter.toChangePack(doc.createChangePack()), }, @@ -502,6 +504,7 @@ export class Client implements Observable { return this.rpcClient .detachDocument( { + clientKey: this.key!, clientId: this.id!, documentId: attachment.docID, changePack: converter.toChangePack(doc.createChangePack()), @@ -691,6 +694,7 @@ export class Client implements Observable { return this.rpcClient .removeDocument( { + clientKey: this.key!, clientId: this.id!, documentId: attachment.docID, changePack: pbChangePack, @@ -806,7 +810,9 @@ export class Client implements Observable { const ac = new AbortController(); const stream = this.rpcClient.watchDocument( { + clientKey: this.key!, clientId: this.id!, + documentKey: docKey, documentId: attachment.docID, }, { @@ -942,6 +948,7 @@ export class Client implements Observable { return this.rpcClient .pushPullChanges( { + clientKey: this.key!, clientId: this.id!, documentId: docID, changePack: converter.toChangePack(reqPack), diff --git a/test/integration/document_test.ts b/test/integration/document_test.ts index 7d7e4884b..ff106e1b4 100644 --- a/test/integration/document_test.ts +++ b/test/integration/document_test.ts @@ -629,19 +629,22 @@ describe('Document', function () { d1.update((root) => { root['k1'] = [1, 2]; }, 'set array'); - await c1.attach(d1); + await c1.attach(d1, { isRealtimeSync: false }); assert.equal(d1.toSortedJSON(), '{"k1":[1,2]}'); const c2 = new yorkie.Client(testRPCAddr); await c2.activate(); const d2 = new yorkie.Document(docKey); - await c2.attach(d2); + await c2.attach(d2, { isRealtimeSync: false }); assert.equal(d2.toSortedJSON(), '{"k1":[1,2]}'); // 02. c1 removes d1 and c2 detaches d2. await c1.remove(d1); await c2.detach(d2); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getStatus(), DocumentStatus.Removed); assert.equal(d2.getStatus(), DocumentStatus.Removed); @@ -660,18 +663,22 @@ describe('Document', function () { d1.update((root) => { root['k1'] = [1, 2]; }, 'set array'); - await c1.attach(d1); + await c1.attach(d1, { isRealtimeSync: false }); assert.equal(d1.toSortedJSON(), '{"k1":[1,2]}'); const c2 = new yorkie.Client(testRPCAddr); await c2.activate(); const d2 = new yorkie.Document(docKey); - await c2.attach(d2); + await c2.attach(d2, { isRealtimeSync: false }); assert.equal(d2.toSortedJSON(), '{"k1":[1,2]}'); // 02. c1 removes d1 and c2 removes d2. await c1.remove(d1); await c2.remove(d2); + + await c1.sync(); + await c2.sync(); + assert.equal(d1.getStatus(), DocumentStatus.Removed); assert.equal(d2.getStatus(), DocumentStatus.Removed); From eb79624cdeca614414492dfd2d6ba6c1f683ea04 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Fri, 19 Jan 2024 19:32:30 +0900 Subject: [PATCH 37/48] Update CHANGELOG.md for v0.4.13 (#731) --- CHANGELOG.md | 8 +++++++- package.json | 2 +- package.publish.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef28de5c3..45e013edf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,17 +7,23 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +## [0.4.13] - 2024-01-19 + ### Added - Implement devtools chrome extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/717 ### Changed +- Reflect interface changes of server DB sharding by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/726 - Complement concurrent editing test cases in Tree by @sejongk in https://github.com/yorkie-team/yorkie-js-sdk/pull/721 +- Export devtools type by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/730 +- Update examples version to v0.4.12 by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/722 ### Fixed -- Fix invalid tree conversion by @hackerwins, @JOOHOJANG in https://github.com/yorkie-team/yorkie-js-sdk/pull/719 +- Fix multiple versions of prosemirror-model were loaded by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/728 +- Fix invalid tree conversion by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/719 ## [0.4.12] - 2024-01-05 diff --git a/package.json b/package.json index 4d1d0ba0f..d31309d67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13-rc2", + "version": "0.4.13", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index 5a57119d6..bc9c552f4 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13-rc2", + "version": "0.4.13", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 3b0cca9f7e2032adfbd0efe34091f31ef1219253 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Mon, 22 Jan 2024 19:31:18 +0900 Subject: [PATCH 38/48] Update examples version to v0.4.13 (#733) --- examples/nextjs-scheduler/package.json | 2 +- examples/profile-stack/package.json | 2 +- examples/react-tldraw/package.json | 2 +- examples/react-todomvc/package.json | 2 +- examples/simultaneous-cursors/package.json | 2 +- examples/vanilla-codemirror6/package.json | 2 +- examples/vanilla-quill/package.json | 2 +- examples/vuejs-kanban/package.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/nextjs-scheduler/package.json b/examples/nextjs-scheduler/package.json index a16620007..b476cc3f5 100644 --- a/examples/nextjs-scheduler/package.json +++ b/examples/nextjs-scheduler/package.json @@ -13,7 +13,7 @@ "react": "18.2.0", "react-calendar": "^4.6.0", "react-dom": "18.2.0", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" }, "devDependencies": { "@types/node": "20.4.2", diff --git a/examples/profile-stack/package.json b/examples/profile-stack/package.json index 806578f86..bea2df3ce 100644 --- a/examples/profile-stack/package.json +++ b/examples/profile-stack/package.json @@ -12,6 +12,6 @@ "vite": "^3.2.7" }, "dependencies": { - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" } } diff --git a/examples/react-tldraw/package.json b/examples/react-tldraw/package.json index 2545beef4..4021e09d1 100644 --- a/examples/react-tldraw/package.json +++ b/examples/react-tldraw/package.json @@ -16,7 +16,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "unique-names-generator": "^4.7.1", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" }, "devDependencies": { "@types/lodash": "^4.14.198", diff --git a/examples/react-todomvc/package.json b/examples/react-todomvc/package.json index 6a8aab3c3..38a7d1d0d 100644 --- a/examples/react-todomvc/package.json +++ b/examples/react-todomvc/package.json @@ -13,7 +13,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "todomvc-app-css": "^2.4.2", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" }, "devDependencies": { "@types/react": "^18.0.24", diff --git a/examples/simultaneous-cursors/package.json b/examples/simultaneous-cursors/package.json index be2184430..27b14167b 100644 --- a/examples/simultaneous-cursors/package.json +++ b/examples/simultaneous-cursors/package.json @@ -11,7 +11,7 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" }, "devDependencies": { "@types/react": "^18.0.37", diff --git a/examples/vanilla-codemirror6/package.json b/examples/vanilla-codemirror6/package.json index aa9495cae..aad8d6190 100644 --- a/examples/vanilla-codemirror6/package.json +++ b/examples/vanilla-codemirror6/package.json @@ -20,6 +20,6 @@ "@codemirror/state": "^6.1.2", "@codemirror/view": "^6.3.1", "codemirror": "^6.0.1", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" } } diff --git a/examples/vanilla-quill/package.json b/examples/vanilla-quill/package.json index 081e792d9..fdfc944d0 100644 --- a/examples/vanilla-quill/package.json +++ b/examples/vanilla-quill/package.json @@ -20,6 +20,6 @@ "quill-cursors": "^4.0.0", "quill-delta": "^5.0.0", "short-unique-id": "^4.4.4", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" } } diff --git a/examples/vuejs-kanban/package.json b/examples/vuejs-kanban/package.json index 888c15bfc..4fda5f5d6 100644 --- a/examples/vuejs-kanban/package.json +++ b/examples/vuejs-kanban/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "vue": "^3.2.41", - "yorkie-js-sdk": "^0.4.12" + "yorkie-js-sdk": "^0.4.13" }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.2", From c0da57b3134d37cd8b113fe2c3aba612e3c89ecf Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Wed, 24 Jan 2024 11:21:33 +0900 Subject: [PATCH 39/48] Follow up work after devtools mvp (#734) Changes: - Update README.md - Import devtools type from yorkie-js-sdk and remove protocol.ts - Adjust style to center the panel - Change Yorkie devtools icon - Fix the issue where the panel doesn't update on page refresh --- package-lock.json | 43 ++-- src/devtools/index.ts | 18 +- src/devtools/protocol.ts | 8 + tools/devtools/README.md | 6 +- tools/devtools/package.json | 4 +- tools/devtools/src/content.ts | 4 +- .../src/devtools/components/Detail.tsx | 14 +- .../devtools/src/devtools/components/Tree.tsx | 30 +-- .../src/devtools/contexts/YorkieSource.tsx | 41 ++-- tools/devtools/src/devtools/index.tsx | 2 +- tools/devtools/src/devtools/panel/styles.css | 2 +- tools/devtools/src/popup/index.tsx | 2 +- tools/devtools/src/port.ts | 37 ++-- tools/devtools/src/protocol.ts | 193 ------------------ 14 files changed, 110 insertions(+), 294 deletions(-) delete mode 100644 tools/devtools/src/protocol.ts diff --git a/package-lock.json b/package-lock.json index e0ab01e46..950e81f48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "yorkie-js-sdk", - "version": "0.4.12", + "version": "0.4.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "yorkie-js-sdk", - "version": "0.4.12", + "version": "0.4.13", "license": "Apache-2.0", "workspaces": [ "examples/*", @@ -72,7 +72,7 @@ "react": "18.2.0", "react-calendar": "^4.6.0", "react-dom": "18.2.0", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/node": "20.4.2", @@ -114,7 +114,7 @@ "examples/profile-stack": { "version": "0.0.0", "dependencies": { - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "vite": "^3.2.7" @@ -179,7 +179,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "unique-names-generator": "^4.7.1", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/lodash": "^4.14.198", @@ -247,7 +247,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "todomvc-app-css": "^2.4.2", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/react": "^18.0.24", @@ -311,7 +311,7 @@ "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/react": "^18.0.37", @@ -347,7 +347,7 @@ "@codemirror/state": "^6.1.2", "@codemirror/view": "^6.3.1", "codemirror": "^6.0.1", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "typescript": "^4.6.4", @@ -411,7 +411,7 @@ "quill-cursors": "^4.0.0", "quill-delta": "^5.0.0", "short-unique-id": "^4.4.4", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@types/color-hash": "^1.0.2", @@ -485,7 +485,7 @@ "version": "0.0.0", "dependencies": { "vue": "^3.2.41", - "yorkie-js-sdk": "^0.4.7" + "yorkie-js-sdk": "^0.4.12" }, "devDependencies": { "@vitejs/plugin-vue": "^3.1.2", @@ -19718,9 +19718,9 @@ "link": true }, "node_modules/yorkie-js-sdk": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.7.tgz", - "integrity": "sha512-bUe2f11TTAxV5nsSvozFNGiiHiVhZy03IGbHWwUxsuGa/JluGQOhlqDuyPLEmaPe62YRJlbbBXJ4WAczTjObaA==", + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.13.tgz", + "integrity": "sha512-6Im/SRxJoGcUOf5nHIQDDZnKbLBDUgD66xZxcrAXvZS4KblQnRU54/MdloIF9BzNJlJGwWSk9KjgYwLY73nntg==", "dependencies": { "@types/google-protobuf": "^3.15.5", "@types/long": "^4.0.1", @@ -19798,7 +19798,8 @@ } }, "tools/devtools": { - "version": "0.0.1", + "name": "yorkie-devtools", + "version": "0.4.13", "dependencies": { "classnames": "^2.3.2", "plasmo": "0.84.0", @@ -19807,7 +19808,7 @@ "react-arborist": "^3.4.0", "react-dom": "18.2.0", "use-resize-observer": "^9.1.0", - "yorkie-js-sdk": "0.4.13-rc" + "yorkie-js-sdk": "0.4.13" }, "devDependencies": { "@types/chrome": "0.0.251", @@ -19854,18 +19855,6 @@ "engines": { "node": ">=14.17" } - }, - "tools/devtools/node_modules/yorkie-js-sdk": { - "version": "0.4.13-rc", - "resolved": "https://registry.npmjs.org/yorkie-js-sdk/-/yorkie-js-sdk-0.4.13-rc.tgz", - "integrity": "sha512-T/0giRrkyX+qrNLZ/yvvJaMA1Roc7veykQ+5u6FliLYZYU4jyZt2+dSOs/6tLpWZO6WNf06wXDtn6vAtxI1TgQ==", - "dependencies": { - "@types/google-protobuf": "^3.15.5", - "@types/long": "^4.0.1", - "google-protobuf": "^3.19.4", - "grpc-web": "^1.3.1", - "long": "^5.2.0" - } } } } diff --git a/src/devtools/index.ts b/src/devtools/index.ts index bdca447df..62e548c10 100644 --- a/src/devtools/index.ts +++ b/src/devtools/index.ts @@ -24,8 +24,11 @@ const unsubsByDocKey = new Map void>>(); /** * `sendToPanel` sends a message to the devtools panel. */ -function sendToPanel(message: DevTools.SDKToPanelMessage): void { - if (!isDevtoolsConnected) { +function sendToPanel( + message: DevTools.SDKToPanelMessage, + options?: { force: boolean }, +): void { + if (!(options?.force || isDevtoolsConnected)) { return; } @@ -100,10 +103,13 @@ export function setupDevtools( return; } - sendToPanel({ - msg: 'doc::available', - docKey: doc.getKey(), - }); + // NOTE(chacha912): Send initial message, in case the devtool panel is already open. + sendToPanel( + { + msg: 'refresh-devtools', + }, + { force: true }, + ); // TODO(hackerwins): We need to ensure that this event listener should be // removed later. diff --git a/src/devtools/protocol.ts b/src/devtools/protocol.ts index a11e97a1f..6cc2077f7 100644 --- a/src/devtools/protocol.ts +++ b/src/devtools/protocol.ts @@ -66,6 +66,14 @@ export type PanelToSDKMessage = * Definition of all messages the SDK can send to the Devtools panel. */ export type SDKToPanelMessage = + /** + * Sent when the dev panel is already opened and listened, + * before the sdk is loaded. If the panel receives this message, + * it will replay its initial "connect" message. + */ + | { + msg: 'refresh-devtools'; + } /** * Sent when the document is available for the panel to watch. */ diff --git a/tools/devtools/README.md b/tools/devtools/README.md index 111153965..e985445fc 100644 --- a/tools/devtools/README.md +++ b/tools/devtools/README.md @@ -2,11 +2,13 @@ Yorkie Devtools is a Chrome extension designed to assist in debugging Yorkie. -Yorkie Devtools +Yorkie Devtools ## Installation -Note: Installation instructions are coming soon. +Download the extension from the [Chrome Web Store](https://chromewebstore.google.com/detail/yorkie-devtools/djhcelgbkggnbipeccnnbafbnljoikkc), and you will see the `Yorkie 🐾` tab in Chrome Developer Tools. + +> Please note that this requires a **development** build of `yorkie-js-sdk` version 0.4.13 or newer. ## Development diff --git a/tools/devtools/package.json b/tools/devtools/package.json index 476c833b4..8f6bfc0e3 100644 --- a/tools/devtools/package.json +++ b/tools/devtools/package.json @@ -1,7 +1,7 @@ { "name": "yorkie-devtools", "displayName": "Yorkie Devtools", - "version": "0.4.13-rc", + "version": "0.4.13", "description": "A browser extension that helps you debug Yorkie.", "homepage": "https://yorkie.dev/", "scripts": { @@ -17,7 +17,7 @@ "react-arborist": "^3.4.0", "react-dom": "18.2.0", "use-resize-observer": "^9.1.0", - "yorkie-js-sdk": "0.4.13-rc" + "yorkie-js-sdk": "0.4.13" }, "devDependencies": { "@types/chrome": "0.0.251", diff --git a/tools/devtools/src/content.ts b/tools/devtools/src/content.ts index 634b48391..c6212ed1e 100644 --- a/tools/devtools/src/content.ts +++ b/tools/devtools/src/content.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import type { FullSDKToPanelMessage } from './protocol'; -import { EventSourceDevPanel, EventSourceSDK } from './protocol'; +import type { FullSDKToPanelMessage } from 'yorkie-js-sdk'; +import { EventSourceDevPanel, EventSourceSDK } from 'yorkie-js-sdk'; let panelPort = null; diff --git a/tools/devtools/src/devtools/components/Detail.tsx b/tools/devtools/src/devtools/components/Detail.tsx index 6e46de005..6f50aaafc 100644 --- a/tools/devtools/src/devtools/components/Detail.tsx +++ b/tools/devtools/src/devtools/components/Detail.tsx @@ -20,9 +20,9 @@ import { useState, useCallback } from 'react'; import { Code } from './Code'; import type { RootTreeNode } from './Tree'; import { CodeIcon, GraphIcon } from '../icons'; -import type { TreeNodeInfo } from '../../protocol'; +import type { Devtools } from 'yorkie-js-sdk'; -type FlatTreeNodeInfo = TreeNodeInfo & { +type FlatTreeNodeInfo = Devtools.TreeNodeInfo & { depth: number; childIndex: number; }; @@ -60,9 +60,13 @@ function TreeNode({ node }: { node: FlatTreeNodeInfo }) { ); } -function TreeGraph({ tree }: { tree: TreeNodeInfo }) { +function TreeGraph({ tree }: { tree: Devtools.TreeNodeInfo }) { const flattenTreeWithDepth = useCallback( - (node: TreeNodeInfo, depth = 0, i = 0): Array => { + ( + node: Devtools.TreeNodeInfo, + depth = 0, + i = 0, + ): Array => { const nodeWithDepth = { ...node, depth, childIndex: i }; const children = (node.children || []).flatMap((child, i) => flattenTreeWithDepth(child, depth + 1, i), @@ -82,7 +86,7 @@ export function TreeDetail({ tree, }: { node: RootTreeNode; - tree: TreeNodeInfo; + tree: Devtools.TreeNodeInfo; }) { const [viewType, setViewType] = useState<'json' | 'graph'>('json'); diff --git a/tools/devtools/src/devtools/components/Tree.tsx b/tools/devtools/src/devtools/components/Tree.tsx index f3b9751f6..41b564387 100644 --- a/tools/devtools/src/devtools/components/Tree.tsx +++ b/tools/devtools/src/devtools/components/Tree.tsx @@ -23,13 +23,7 @@ import useResizeObserver from 'use-resize-observer'; import { useSeletedNode } from '../contexts/SeletedNode'; import { useSeletedPresence } from '../contexts/SeletedPresence'; import { sendToSDK } from '../../port'; -import type { - Client, - JSONElement, - ElementValue, - ElementType, - Json, -} from '../../protocol'; +import type { Devtools } from 'yorkie-js-sdk'; import { ArrayIcon, @@ -41,26 +35,20 @@ import { UserIcon, } from '../icons'; -export type RootTreeNode = { +export type RootTreeNode = Devtools.JSONElement & { id: string; path: string; - key: string; - createdAt: string; - value: ElementValue; - type: ElementType; isLastChild?: boolean; }; -type UserNode = { - clientID: string; - presence: Json; +type UserNode = Devtools.Client & { id: string; type: 'USER'; }; type PresenceJsonNode = { id: string; key: string; - value: Json; + value: Devtools.Json; isLastChild: boolean; type: 'JSON'; }; @@ -240,7 +228,7 @@ function rootChildAccessor(node: RootTreeNode): Array { if (!(node.type === 'YORKIE_OBJECT' || node.type === 'YORKIE_ARRAY')) { return null; } - const children = Object.values(node.value) as Array; + const children = Object.values(node.value) as Array; const length = children.length; const res = children.map((v, i) => { const path = `${node.path}.${v.key}`; @@ -285,7 +273,11 @@ function presenceChildAccessor( /** * `PresenceTree` renders the presences of the document. */ -export function PresenceTree({ presences }: { presences: Array }) { +export function PresenceTree({ + presences, +}: { + presences: Array; +}) { const { ref, width, height } = useResizeObserver(); const data = useMemo(() => { const presenceNodes: Array = presences.map((client) => ({ @@ -317,7 +309,7 @@ export function PresenceTree({ presences }: { presences: Array }) { /** * `RootTree` renders the root object of the document. */ -export function RootTree({ root }: { root: JSONElement }) { +export function RootTree({ root }: { root: Devtools.JSONElement }) { const { ref, width, height } = useResizeObserver(); const data = useMemo(() => { const rootNode: Array = root diff --git a/tools/devtools/src/devtools/contexts/YorkieSource.tsx b/tools/devtools/src/devtools/contexts/YorkieSource.tsx index 41fee9c8b..317dc7481 100644 --- a/tools/devtools/src/devtools/contexts/YorkieSource.tsx +++ b/tools/devtools/src/devtools/contexts/YorkieSource.tsx @@ -23,18 +23,13 @@ import { useState, } from 'react'; -import type { - JSONElement, - Client, - SDKToPanelMessage, - TreeNodeInfo, -} from '../../protocol'; -import { onPortMessage, sendToSDK } from '../../port'; +import type { Devtools, SDKToPanelMessage } from 'yorkie-js-sdk'; +import { connectPort, sendToSDK } from '../../port'; const DocKeyContext = createContext(null); -const RootContext = createContext(null); -const PresencesContext = createContext | null>(null); -const NodeDetailContext = createContext(null); +const RootContext = createContext(null); +const PresencesContext = createContext | null>(null); +const NodeDetailContext = createContext(null); type Props = { children?: ReactNode; @@ -42,12 +37,16 @@ type Props = { export function YorkieSourceProvider({ children }: Props) { const [currentDocKey, setCurrentDocKey] = useState(''); - const [root, setRoot] = useState(null); - const [presences, setPresences] = useState>([]); + const [root, setRoot] = useState(null); + const [presences, setPresences] = useState>([]); const [nodeDetail, setNodeDetail] = useState(null); const handleSDKMessage = useCallback((message: SDKToPanelMessage) => { switch (message.msg) { + case 'refresh-devtools': + setCurrentDocKey(''); + sendToSDK({ msg: 'devtools::connect' }); + break; case 'doc::available': setCurrentDocKey(message.docKey); sendToSDK({ @@ -73,11 +72,23 @@ export function YorkieSourceProvider({ children }: Props) { } }, []); + const handlePortDisconnect = useCallback(() => { + setCurrentDocKey(''); + }, []); + useEffect(() => { - sendToSDK({ msg: 'devtools::connect' }); - onPortMessage.addListener(handleSDKMessage); + connectPort(handleSDKMessage, handlePortDisconnect); + + const tabID = chrome.devtools.inspectedWindow.tabId; + const handleInspectedTabUpdate = (id, { status }) => { + // NOTE(chacha912): The inspected window is reloaded, so we should reconnect the port. + if (status === 'complete' && tabID === id) { + connectPort(handleSDKMessage, handlePortDisconnect); + } + }; + chrome.tabs.onUpdated.addListener(handleInspectedTabUpdate); return () => { - onPortMessage.removeListener(handleSDKMessage); + chrome.tabs.onUpdated.removeListener(handleInspectedTabUpdate); }; }, []); diff --git a/tools/devtools/src/devtools/index.tsx b/tools/devtools/src/devtools/index.tsx index 28c30dea0..3c894d2a7 100644 --- a/tools/devtools/src/devtools/index.tsx +++ b/tools/devtools/src/devtools/index.tsx @@ -17,7 +17,7 @@ import yorkiePanelHTML from 'url:./panel/index.html'; chrome.devtools.panels.create( - '🐶 Yorkie', + 'Yorkie 🐾', '', // See: https://github.com/PlasmoHQ/plasmo/issues/106#issuecomment-1188539625 yorkiePanelHTML.split('/').pop(), diff --git a/tools/devtools/src/devtools/panel/styles.css b/tools/devtools/src/devtools/panel/styles.css index 246a40b58..9447b3680 100644 --- a/tools/devtools/src/devtools/panel/styles.css +++ b/tools/devtools/src/devtools/panel/styles.css @@ -40,7 +40,7 @@ display: flex; flex-direction: column; align-items: center; - padding-top: 30%; + justify-content: center; height: 100vh; color: var(--gray-900); line-height: 1.4; diff --git a/tools/devtools/src/popup/index.tsx b/tools/devtools/src/popup/index.tsx index 2859a24ae..26f489ed5 100644 --- a/tools/devtools/src/popup/index.tsx +++ b/tools/devtools/src/popup/index.tsx @@ -23,7 +23,7 @@ function Popup() { color: '#333', }} > - Please open the developer tools, and "🐶 Yorkie" tab will be shown. + Please open the developer tools, and "Yorkie 🐾" tab will be shown.
); } diff --git a/tools/devtools/src/port.ts b/tools/devtools/src/port.ts index f4c5b49bd..b69a95cb0 100644 --- a/tools/devtools/src/port.ts +++ b/tools/devtools/src/port.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import type { PanelToSDKMessage } from './protocol'; -import { EventSourceDevPanel } from './protocol'; +import { EventSourceDevPanel } from 'yorkie-js-sdk'; +import type { PanelToSDKMessage } from 'yorkie-js-sdk'; const tabID = chrome.devtools.inspectedWindow.tabId; @@ -24,12 +24,21 @@ const tabID = chrome.devtools.inspectedWindow.tabId; // inspected window of a Devtools extension. // For more details: https://developer.chrome.com/docs/extensions/develop/concepts/messaging#connect let port: chrome.runtime.Port; -port = chrome.tabs.connect(tabID, { - name: EventSourceDevPanel, -}); -port.onDisconnect.addListener(() => { - port = undefined; -}); +export const connectPort = (onMessage, onDisconnect) => { + port = chrome.tabs.connect(tabID, { + name: EventSourceDevPanel, + }); + + port.onMessage.addListener(onMessage); + port.onDisconnect.addListener(() => { + port.onMessage.removeListener(onMessage); + onDisconnect(); + port = undefined; + }); + + sendToSDK({ msg: 'devtools::connect' }); + return port; +}; export const sendToSDK = (message: PanelToSDKMessage) => { if (!port) return; @@ -38,15 +47,3 @@ export const sendToSDK = (message: PanelToSDKMessage) => { ...message, }); }; - -export const onPortMessage = port.onMessage; - -// TODO(chacha912): The inspected window was reloaded, so we should reload the panel. -// Ideally, we should reconnect instead of performing a full reload. -// TODO(hackerwins): We need to ensure that this event listener should be -// removed later. -chrome.tabs.onUpdated.addListener((id, { status }) => { - if (status === 'complete' && tabID === id) { - window.location.reload(); - } -}); diff --git a/tools/devtools/src/protocol.ts b/tools/devtools/src/protocol.ts deleted file mode 100644 index b3bf85f91..000000000 --- a/tools/devtools/src/protocol.ts +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2024 The Yorkie Authors. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * TODO(chacha912): This code is a copy from src/devtools/protocol.ts. - * It is intended to be used by importing it from yorkie-js-sdk when - * it is structured as a monorepo. - */ -import type { DocEvent, PrimitiveValue } from 'yorkie-js-sdk'; - -/** - * `EventSourceDevPanel` is the name of the source representing messages - * from the Devtools panel. - */ -export const EventSourceDevPanel = 'yorkie-devtools-panel'; - -/** - * `EventSourceSDK` is the name of the source representing messages - * from the SDK. - */ -export const EventSourceSDK = 'yorkie-devtools-sdk'; - -/** - * Definition of all messages the Devtools panel can send to the SDK. - */ -export type PanelToSDKMessage = - /** - * Initial message from the panel to the SDK. It is sent when the panel is opened. - */ - | { msg: 'devtools::connect' } - /** - * Sent when the panel is not available. - */ - | { msg: 'devtools::disconnect' } - /** - * Informs the SDK that the panel is interested in receiving the "event" for the document, - * starting with the initial "full sync" event. - */ - | { - msg: 'devtools::subscribe'; - docKey: string; - } - /** - * Requests the detailed information for the node corresponding to the given path. - */ - | { - msg: 'devtools::node::detail'; - data: { - path: string; - type: string; - }; - }; - -/** - * Definition of all messages the SDK can send to the Devtools panel. - */ -export type SDKToPanelMessage = - /** - * Sent when the document is available for the panel to watch. - */ - | { - msg: 'doc::available'; - docKey: string; - } - /** - * Sent initially, to synchronize the entire current state of the document. - */ - | { - msg: 'doc::sync::full'; - docKey: string; - root: JSONElement; - clients: Array; - } - /** - * Sent whenever the document is updated. - */ - | { - msg: 'doc::sync::partial'; - docKey: string; - event?: DocEvent; - root?: JSONElement; - clients?: Array; - } - /** - * Sent detailed information for the node corresponding to the given path. - */ - | { - msg: 'doc::node::detail'; - node: TreeNodeInfo; - }; - -export type FullPanelToSDKMessage = PanelToSDKMessage & { - source: 'yorkie-devtools-panel'; -}; - -export type FullSDKToPanelMessage = SDKToPanelMessage & { - source: 'yorkie-devtools-sdk'; -}; - -/** - * TODO(chacha912): This code is a copy from src/types/devtools.ts. - * It is intended to be used by importing it from yorkie-js-sdk when - * it is structured as a monorepo. - */ - -/** - * `Json` represents a JSON value. - * - * TODO(hackerwins): We need to replace `Indexable` with `Json`. - */ -export type Json = - | string - | number - | boolean - // eslint-disable-next-line @typescript-eslint/ban-types - | null - | { [key: string]: Json } - | Array; - -/** - * `Client` represents a client value in devtools. - */ -export type Client = { - clientID: string; - presence: Json; -}; - -/** - * `JSONElement` represents the result of `Element.toJSForTest()`. - */ -export type JSONElement = { - type: JSONElementType; - key?: string; - value: JSONElementValue; - createdAt: string; -}; - -type JSONElementType = - | 'YORKIE_PRIMITIVE' - | 'YORKIE_COUNTER' - | 'YORKIE_OBJECT' - | 'YORKIE_ARRAY' - | 'YORKIE_TEXT' - | 'YORKIE_TREE'; - -/** - * `ElementValue` represents the result of `Element.toJSForTest()`. - * - * NOTE(chacha912): Json type is used to represent the result of - * `Text.toJSForTest()` and `Tree.toJSForTest()`. - */ -type JSONElementValue = - | PrimitiveValue - | ContainerValue // Array | Object - | Json; // Text | Tree - -/** - * `ContainerValue` represents the result of `Array.toJSForTest()` and - * `Object.toJSForTest()`. - */ -export type ContainerValue = { - [key: string]: JSONElement; -}; - -/** - * `TreeNodeInfo` represents the tree node information in devtools. - */ -export type TreeNodeInfo = { - id: string; - type: string; - parent?: string; - size: number; - value?: string; - removedAt?: string; - isRemoved: boolean; - insPrev?: string; - insNext?: string; - children: Array; - depth: number; -}; From 1fcd6b0c1e81c89575679b03c3316029989eb896 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Wed, 24 Jan 2024 19:54:57 +0900 Subject: [PATCH 40/48] Add design document for devtools extension (#735) --- design/README.md | 25 +++++++++ design/devtools.md | 72 +++++++++++++++++++++++++ design/media/devtools-extension.png | Bin 0 -> 35864 bytes design/media/devtools-lifecycle1.png | Bin 0 -> 120379 bytes design/media/devtools-lifecycle2.png | Bin 0 -> 117448 bytes design/media/devtools-message-flow.png | Bin 0 -> 121283 bytes design/template.md | 27 ++++++++++ 7 files changed, 124 insertions(+) create mode 100644 design/README.md create mode 100644 design/devtools.md create mode 100644 design/media/devtools-extension.png create mode 100644 design/media/devtools-lifecycle1.png create mode 100644 design/media/devtools-lifecycle2.png create mode 100644 design/media/devtools-message-flow.png create mode 100644 design/template.md diff --git a/design/README.md b/design/README.md new file mode 100644 index 000000000..5a263e295 --- /dev/null +++ b/design/README.md @@ -0,0 +1,25 @@ +# Design Document + +## Contents + +- [Devtools Extension](devtools.md): Message flow between devtools extension and yorkie-js-sdk + +## Maintaining the Document + +For significant scope and complex new features, it is recommended to write a +Design Document before starting any implementation work. On the other hand, we +don't need to design documentation for small, simple features and bug fixes. + +Writing a design document for big features has many advantages: + +- It helps new visitors or contributors understand the inner workings or the + architecture of the project. +- We can agree with the community before code is written that could waste effort + in the wrong direction. + +While working on your design, writing code to prototype your functionality may +be useful to refine your approach. + +Authoring Design document is also proceeded in the same +[contribution flow](../CONTRIBUTING.md) as normal Pull Request such as function +implementation or bug fixing. diff --git a/design/devtools.md b/design/devtools.md new file mode 100644 index 000000000..ff7b59829 --- /dev/null +++ b/design/devtools.md @@ -0,0 +1,72 @@ +--- +title: devtools +target-version: 0.4.13 +--- + +# Devtools + +## Summary + +[Yorkie Devtools](https://github.com/yorkie-team/yorkie-js-sdk/tree/main/tools/devtools) is a Chrome extension designed to assist in debugging Yorkie. The devtools extension consists of a `panel` that displays Yorkie data and a `content script` for communication. This document examines the configuration of the extension and explains how it communicates with the yorkie-js-sdk. + +### Goals + +This document aims to help new SDK contributors understand overall message flow of the extension. + +### Non-Goals + +While this document explains the communication process and data flow within devtools, it does not cover the specifics of the data exchanged or how received data is presented. + +## Proposal Details + +### Devtools Extension Configuration and Message Flow + +A Chrome extension consists of various files, including popups, content scripts, background scripts, etc. Among them, Yorkie Devtools utilizes a `devtools panel` to display Yorkie data and a `content script` to communicate with the SDK. + +- [Devtools Panels](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/devtools_panels) + - When an extension provides tools useful for developers, it can add a UI for them within the browser's developer tools as a new panel. + - `Yorkie 🐾` panel displays Yorkie data and is built using React. ([Code](https://github.com/yorkie-team/yorkie-js-sdk/blob/c0da57b3134d37cd8b113fe2c3aba612e3c89ecf/tools/devtools/src/devtools/panel/index.tsx)) +- [Content Scripts](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts) + - Content scripts are injected into web pages within the browser and share the context with the page, allowing access to the page's content using DOM APIs. ([Code](https://github.com/yorkie-team/yorkie-js-sdk/blob/c0da57b3134d37cd8b113fe2c3aba612e3c89ecf/tools/devtools/src/content.ts)) + +Devtools Extension + +Content scripts play a role in passing messages between the panel and the SDK. To enable this communication between the panel and the SDK within webpages, appropriate APIs are used for each context. Communication between content script and the panel relies on Chrome's `port.postMessage` and `port.onMessage.addListener`, while communication between content script and the SDK relies on DOM's `window.postMessage` and `window.addEventListener` APIs. + +The diagram below illustrates the flow when the devtools panel "requests data" from the SDK. The panel initiates a connection to the inspected window and requests messages. The content script then relays the received message from the panel to the SDK, and the SDK subsequently forwards the message back to the panel. + +![Devtools Message Flow](media/devtools-message-flow.png) + +### Devtools Panel Lifecycle + +Let's examine the lifecycle of interaction between the devtools panel and the SDK in two scenarios: + +| ![Devtools life cycle 1](media/devtools-lifecycle1.png) | ![Devtools life cycle 2](media/devtools-lifecycle2.png) | +| :-----------------------------------------------------: | :-------------------------------------------------------: | +| When the devtools panel is opened after page load | When the devtools panel is open, and a new page is loaded | + +#### 1. When the Devtools Panel Is Opened After Page Load + +1. Upon opening the panel, it establishes a connection with the currently inspected window. + [tabs.connect()](https://developer.chrome.com/docs/extensions/develop/concepts/messaging#connect) creates a reusable channel (port) for long-term message passing between the panel and a content script. +2. The content script confirms the port connection using `chrome.runtime.onConnect`. +3. The panel, after establishing the port connection, sends a `devtools::connect` message to the SDK. + The content script plays a role in relaying messages between the panel and the SDK. +4. The SDK, upon receiving the `devtools::connect` message, sends a `doc::available` message to the panel, including the currently connected document key. +5. The panel, upon receiving the document key, sends a `devtools::subscribe` message to indicate its intention to subscribe to the corresponding document. +6. The SDK, upon receiving the `devtools::subscribe` message, initiates synchronization. Initially, it sends a `doc::sync::full` message with all document information, and subsequently, it sends `doc::sync::partial` data whenever there are changes to the document. +7. When the panel is closed, it is detected by the content script using `port.onDisconnect`, which then sends a `devtools::disconnect` message to the SDK. +8. The SDK, upon detecting the panel disconnection, stops synchronization. + +#### 2. When the Devtools Panel Is Open, and a New Page Is Loaded + +1. Upon reloading the page, the existing port connection of the panel is closed. Upon completion of the new page load (`chrome.tabs.onUpdated`), a new port connection is established. +2. The content script confirms the new port connection using `chrome.runtime.onConnect`. +3. The panel, after establishing the port connection, sends a `devtools::connect` message to the SDK. + If yorkie-js-sdk is not ready at this point, no action is taken. +4. Subsequently, when yorkie-js-sdk creates a new document and executes the [setup devtools](https://github.com/yorkie-team/yorkie-js-sdk/blob/c0da57b3134d37cd8b113fe2c3aba612e3c89ecf/src/devtools/index.ts#L98), it sends a `refresh-devtools` message. +5. The panel, upon receiving the `refresh-devtools` message, sends `devtools::connect` message. The subsequent steps are identical to those in the first scenario (steps 1-4 to 1-8). + +### Risks and Mitigation + +Currently, Yorkie devtools can only inspect the entire data for changes to documents and presence. In the future, we plan to enhance devtools to show operations and changes, as well as introduce a time travel feature to observe how documents change when operations are applied. diff --git a/design/media/devtools-extension.png b/design/media/devtools-extension.png new file mode 100644 index 0000000000000000000000000000000000000000..1e5fc4d5e16cfd0627d9be892b609da9acb74234 GIT binary patch literal 35864 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≪^|>;SJ~g^C+?;G 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 literal 0 HcmV?d00001 diff --git a/design/media/devtools-lifecycle2.png b/design/media/devtools-lifecycle2.png new file mode 100644 index 0000000000000000000000000000000000000000..b72b72afcda26fdf28d5acb0b25b835ecfd47db6 GIT binary patch literal 117448 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 TX-_v6{7+t5MXKP2ng9O>Ud=Bw literal 0 HcmV?d00001 diff --git a/design/media/devtools-message-flow.png b/design/media/devtools-message-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..4222fb97850459e7d141a89b4c3a3522b96b110b GIT binary patch literal 121283 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 Lbd+-x?>zoL$g+5q literal 0 HcmV?d00001 diff --git a/design/template.md b/design/template.md new file mode 100644 index 000000000..8aff48b3b --- /dev/null +++ b/design/template.md @@ -0,0 +1,27 @@ +--- +title: feature-name +--- + +# Feature Name + +## Summary + +Write a brief description of the feature here. + +### Goals + +List the specific goals of the proposal. How will we know that this has succeeded? + +### Non-Goals + +What is out of scope for this proposal? Listing non-goals helps to focus discussion +and make progress. + +## Proposal Details + +This is where we detail how to use the feature with snippet or API and describe +the internal implementation. + +### Risks and Mitigation + +What are the risks of this proposal and how do we mitigate. From d716e83bca598afef5f6b9e1875b5d4841f2c677 Mon Sep 17 00:00:00 2001 From: LeeJongBeom <52884648+devleejb@users.noreply.github.com> Date: Thu, 25 Jan 2024 12:57:49 +0900 Subject: [PATCH 41/48] Export `LogLevel` and `setLogLevel` (#737) This commit exposes the setLogLevel function and LogLevel type, allowing SDK users to modify the log level. This prevents unintended logging from the user. --- src/yorkie.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/yorkie.ts b/src/yorkie.ts index 0730b48f1..98135d3f2 100644 --- a/src/yorkie.ts +++ b/src/yorkie.ts @@ -107,6 +107,9 @@ export { export { Change } from '@yorkie-js-sdk/src/document/change/change'; export { converter } from '@yorkie-js-sdk/src/api/converter'; +export type { LogLevel } from '@yorkie-js-sdk/src/util/logger'; +export { setLogLevel } from '@yorkie-js-sdk/src/util/logger'; + export { EventSourceDevPanel, EventSourceSDK, From d9f5eb155c4871fb56b01465096a92e9254548ce Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Thu, 25 Jan 2024 15:37:58 +0900 Subject: [PATCH 42/48] Fix invalid TreeChanges in concurrent Tree.Style (#738) --- src/document/crdt/rht.ts | 8 ++- src/document/crdt/tree.ts | 22 ++++---- test/integration/tree_test.ts | 102 +++++++++++++++++++++++++++++----- 3 files changed, 105 insertions(+), 27 deletions(-) diff --git a/src/document/crdt/rht.ts b/src/document/crdt/rht.ts index 194579681..e4ebfd8da 100644 --- a/src/document/crdt/rht.ts +++ b/src/document/crdt/rht.ts @@ -138,9 +138,11 @@ export class RHT { return ''; } - return ` ${[...this.nodeMapByKey] - .map(([k, v]) => `${k}="${JSON.parse(v.getValue())}"`) - .join(' ')}`; + const attrs = [...this.nodeMapByKey] + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([k, v]) => `${k}="${JSON.parse(v.getValue())}"`); + + return ` ${attrs.join(' ')}`; } /** diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index d8de4d185..236f40419 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -745,17 +745,9 @@ export class CRDTTree extends CRDTGCElement { editedAt, ); const [toParent, toLeft] = this.findNodesAndSplitText(range[1], editedAt); - const changes: Array = []; - changes.push({ - type: TreeChangeType.Style, - from: this.toIndex(fromParent, fromLeft), - to: this.toIndex(toParent, toLeft), - fromPath: this.toPath(fromParent, fromLeft), - toPath: this.toPath(toParent, toLeft), - actor: editedAt.getActorID()!, - value: attributes ? parseObjectValues(attributes) : undefined, - }); + const changes: Array = []; + const value = attributes ? parseObjectValues(attributes) : undefined; this.traverseInPosRange( fromParent, fromLeft, @@ -770,6 +762,16 @@ export class CRDTTree extends CRDTGCElement { for (const [key, value] of Object.entries(attributes)) { node.attrs.set(key, value, editedAt); } + + changes.push({ + type: TreeChangeType.Style, + from: this.toIndex(fromParent, fromLeft), + to: this.toIndex(toParent, toLeft), + fromPath: this.toPath(fromParent, fromLeft), + toPath: this.toPath(toParent, toLeft), + actor: editedAt.getActorID()!, + value, + }); } }, ); diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index 890af8e30..f0ad7c2e5 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -20,7 +20,10 @@ import { toDocKey, withTwoClientsAndDocuments, } from '@yorkie-js-sdk/test/integration/integration_helper'; -import { TreeEditOpInfo } from '@yorkie-js-sdk/src/document/operation/operation'; +import { + TreeEditOpInfo, + TreeStyleOpInfo, +} from '@yorkie-js-sdk/src/document/operation/operation'; import { Document } from '@yorkie-js-sdk/src/document/document'; describe('Tree', () => { @@ -1119,12 +1122,12 @@ describe('Tree.style', function () { assert.equal( d1.getRoot().t.toXML(), - /*html*/ `

hello

`, + /*html*/ `

hello

`, ); assert.equal( d2.getRoot().t.toXML(), - /*html*/ `

hello

`, + /*html*/ `

hello

`, ); }, task.name); }); @@ -1162,28 +1165,28 @@ describe('Tree.style', function () { root.t.style(3, 4, { color: 'red' }); assert.equal( root.t.toXML(), - /*html*/ `

ab

cd

`, + /*html*/ `

ab

cd

`, ); // style attributes with the whole root.t.style(0, 4, { size: 'small' }); assert.equal( root.t.toXML(), - /*html*/ `

ab

cd

`, + /*html*/ `

ab

cd

`, ); // 02. style attributes to elements. root.t.style(0, 5, { style: 'italic' }); assert.equal( root.t.toXML(), - /*html*/ `

ab

cd

`, + /*html*/ `

ab

cd

`, ); // 03. Ignore styling attributes to text nodes. root.t.style(1, 3, { bold: 'true' }); assert.equal( root.t.toXML(), - /*html*/ `

ab

cd

`, + /*html*/ `

ab

cd

`, ); }); }); @@ -3977,14 +3980,85 @@ describe('TreeChange', () => { ); }, task.name); }); + + it('Concurrent delete and style', async function ({ task }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'root', + children: [ + { type: 't', attributes: { id: '1', value: 'init' }, children: [] }, + { type: 't', attributes: { id: '2', value: 'init' }, children: [] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ ``, + ); + + const [ops1, ops2] = subscribeDocs(d1, d2); + + d1.update((root) => root.t.styleByPath([0], { value: 'changed' })); + d2.update((root) => root.t.editByPath([0], [1])); + await c1.sync(); + await c2.sync(); + await c1.sync(); + assert.equal(d1.getRoot().t.toXML(), d2.getRoot().t.toXML()); + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ ``, + ); + + assert.deepEqual( + ops1.map((it) => { + return { type: it.type, from: it.from, to: it.to, value: it.value }; + }), + [ + { + type: 'tree-style', + from: 0, + to: 1, + value: { value: 'changed' }, + } as any, + { + type: 'tree-edit', + from: 0, + to: 2, + value: undefined, + } as any, + ], + ); + + assert.deepEqual( + ops2.map((it) => { + return { type: it.type, from: it.from, to: it.to, value: it.value }; + }), + [ + { + type: 'tree-edit', + from: 0, + to: 2, + value: undefined, + } as any, + ], + ); + }, task.name); + }); }); function subscribeDocs( d1: Document<{ t: Tree }>, d2: Document<{ t: Tree }>, -): [Array, Array] { - const ops1: Array = []; - const ops2: Array = []; +): [ + Array, + Array, +] { + const ops1: Array = []; + const ops2: Array = []; d1.subscribe('$.t', (event) => { if (event.type === 'local-change' || event.type === 'remote-change') { @@ -3992,8 +4066,8 @@ function subscribeDocs( ops1.push( ...(operations.filter( - (op) => op.type === 'tree-edit', - ) as Array), + (op) => op.type === 'tree-edit' || op.type === 'tree-style', + ) as Array), ); } }); @@ -4004,8 +4078,8 @@ function subscribeDocs( ops2.push( ...(operations.filter( - (op) => op.type === 'tree-edit', - ) as Array), + (op) => op.type === 'tree-edit' || op.type === 'tree-style', + ) as Array), ); } }); From 1f465d753346f6fe79926a289d7125a9f0579f5c Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Thu, 25 Jan 2024 17:59:41 +0900 Subject: [PATCH 43/48] Update CHANGELOG.md for v0.4.14-rc (#739) --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e013edf..45c27f881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +### Added + +- Add design document for devtools extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/735 +- Export LogLevel and setLogLevel @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/737 + +### Fixed + +- Follow up work after devtools mvp by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/734 +- Fix invalid TreeChanges in concurrent Tree.Style by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/738 + ## [0.4.13] - 2024-01-19 ### Added diff --git a/package.json b/package.json index d31309d67..d351990ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13", + "version": "0.4.14-rc", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index bc9c552f4..d89b5f91a 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.13", + "version": "0.4.14-rc", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 28825787f433ddfc0cc8273eb228e58fff09047b Mon Sep 17 00:00:00 2001 From: Sejong Kim <46182768+sejongk@users.noreply.github.com> Date: Fri, 26 Jan 2024 19:41:52 +0900 Subject: [PATCH 44/48] Restore interface changes due to server DB sharding (#740) This commit restores passing sharding keys to the SDK in accordance with yorkie-team/yorkie#776. --- src/api/yorkie/v1/yorkie.proto | 9 ------- src/api/yorkie/v1/yorkie_pb.d.ts | 45 -------------------------------- src/api/yorkie/v1/yorkie_pb.js | 9 ------- src/client/client.ts | 7 ----- 4 files changed, 70 deletions(-) diff --git a/src/api/yorkie/v1/yorkie.proto b/src/api/yorkie/v1/yorkie.proto index 0d4736778..279f96f98 100644 --- a/src/api/yorkie/v1/yorkie.proto +++ b/src/api/yorkie/v1/yorkie.proto @@ -48,7 +48,6 @@ message ActivateClientResponse { } message DeactivateClientRequest { - string client_key = 2; string client_id = 1; } @@ -56,7 +55,6 @@ message DeactivateClientResponse { } message AttachDocumentRequest { - string client_key = 3; string client_id = 1; ChangePack change_pack = 2; } @@ -67,7 +65,6 @@ message AttachDocumentResponse { } message DetachDocumentRequest { - string client_key = 5; string client_id = 1; string document_id = 2; ChangePack change_pack = 3; @@ -79,9 +76,7 @@ message DetachDocumentResponse { } message WatchDocumentRequest { - string client_key = 4; string client_id = 1; - string document_key = 3; string document_id = 2; } @@ -97,7 +92,6 @@ message WatchDocumentResponse { } message RemoveDocumentRequest { - string client_key = 4; string client_id = 1; string document_id = 2; ChangePack change_pack = 3; @@ -108,7 +102,6 @@ message RemoveDocumentResponse { } message PushPullChangesRequest { - string client_key = 5; string client_id = 1; string document_id = 2; ChangePack change_pack = 3; @@ -120,9 +113,7 @@ message PushPullChangesResponse { } message BroadcastRequest { - string client_key = 6; string client_id = 1; - string document_key = 5; string document_id = 2; string topic = 3; bytes payload = 4; diff --git a/src/api/yorkie/v1/yorkie_pb.d.ts b/src/api/yorkie/v1/yorkie_pb.d.ts index 18552637f..0c685f6ad 100644 --- a/src/api/yorkie/v1/yorkie_pb.d.ts +++ b/src/api/yorkie/v1/yorkie_pb.d.ts @@ -74,11 +74,6 @@ export declare class ActivateClientResponse extends Message { - /** - * @generated from field: string client_key = 2; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ @@ -122,11 +117,6 @@ export declare class DeactivateClientResponse extends Message { - /** - * @generated from field: string client_key = 3; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ @@ -185,11 +175,6 @@ export declare class AttachDocumentResponse extends Message { - /** - * @generated from field: string client_key = 5; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ @@ -253,21 +238,11 @@ export declare class DetachDocumentResponse extends Message { - /** - * @generated from field: string client_key = 4; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ clientId: string; - /** - * @generated from field: string document_key = 3; - */ - documentKey: string; - /** * @generated from field: string document_id = 2; */ @@ -352,11 +327,6 @@ export declare class WatchDocumentResponse_Initialization extends Message { - /** - * @generated from field: string client_key = 4; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ @@ -415,11 +385,6 @@ export declare class RemoveDocumentResponse extends Message { - /** - * @generated from field: string client_key = 5; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ @@ -483,21 +448,11 @@ export declare class PushPullChangesResponse extends Message { - /** - * @generated from field: string client_key = 6; - */ - clientKey: string; - /** * @generated from field: string client_id = 1; */ clientId: string; - /** - * @generated from field: string document_key = 5; - */ - documentKey: string; - /** * @generated from field: string document_id = 2; */ diff --git a/src/api/yorkie/v1/yorkie_pb.js b/src/api/yorkie/v1/yorkie_pb.js index 2e00b36b5..97b8ad6e8 100644 --- a/src/api/yorkie/v1/yorkie_pb.js +++ b/src/api/yorkie/v1/yorkie_pb.js @@ -50,7 +50,6 @@ const ActivateClientResponse = proto3.makeMessageType( const DeactivateClientRequest = proto3.makeMessageType( "yorkie.v1.DeactivateClientRequest", () => [ - { no: 2, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ], ); @@ -69,7 +68,6 @@ const DeactivateClientResponse = proto3.makeMessageType( const AttachDocumentRequest = proto3.makeMessageType( "yorkie.v1.AttachDocumentRequest", () => [ - { no: 3, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "change_pack", kind: "message", T: ChangePack }, ], @@ -92,7 +90,6 @@ const AttachDocumentResponse = proto3.makeMessageType( const DetachDocumentRequest = proto3.makeMessageType( "yorkie.v1.DetachDocumentRequest", () => [ - { no: 5, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "change_pack", kind: "message", T: ChangePack }, @@ -116,9 +113,7 @@ const DetachDocumentResponse = proto3.makeMessageType( const WatchDocumentRequest = proto3.makeMessageType( "yorkie.v1.WatchDocumentRequest", () => [ - { no: 4, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 3, name: "document_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ], ); @@ -151,7 +146,6 @@ const WatchDocumentResponse_Initialization = proto3.makeMessageType( const RemoveDocumentRequest = proto3.makeMessageType( "yorkie.v1.RemoveDocumentRequest", () => [ - { no: 4, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "change_pack", kind: "message", T: ChangePack }, @@ -174,7 +168,6 @@ const RemoveDocumentResponse = proto3.makeMessageType( const PushPullChangesRequest = proto3.makeMessageType( "yorkie.v1.PushPullChangesRequest", () => [ - { no: 5, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "change_pack", kind: "message", T: ChangePack }, @@ -198,9 +191,7 @@ const PushPullChangesResponse = proto3.makeMessageType( const BroadcastRequest = proto3.makeMessageType( "yorkie.v1.BroadcastRequest", () => [ - { no: 6, name: "client_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 5, name: "document_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "document_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 4, name: "payload", kind: "scalar", T: 12 /* ScalarType.BYTES */ }, diff --git a/src/client/client.ts b/src/client/client.ts index 3ad744e5c..b29b64d20 100644 --- a/src/client/client.ts +++ b/src/client/client.ts @@ -388,7 +388,6 @@ export class Client implements Observable { return this.rpcClient .deactivateClient( { - clientKey: this.key!, clientId: this.id!, }, { headers: { 'x-shard-key': this.apiKey } }, @@ -436,7 +435,6 @@ export class Client implements Observable { return this.rpcClient .attachDocument( { - clientKey: this.key!, clientId: this.id!, changePack: converter.toChangePack(doc.createChangePack()), }, @@ -504,7 +502,6 @@ export class Client implements Observable { return this.rpcClient .detachDocument( { - clientKey: this.key!, clientId: this.id!, documentId: attachment.docID, changePack: converter.toChangePack(doc.createChangePack()), @@ -694,7 +691,6 @@ export class Client implements Observable { return this.rpcClient .removeDocument( { - clientKey: this.key!, clientId: this.id!, documentId: attachment.docID, changePack: pbChangePack, @@ -810,9 +806,7 @@ export class Client implements Observable { const ac = new AbortController(); const stream = this.rpcClient.watchDocument( { - clientKey: this.key!, clientId: this.id!, - documentKey: docKey, documentId: attachment.docID, }, { @@ -948,7 +942,6 @@ export class Client implements Observable { return this.rpcClient .pushPullChanges( { - clientKey: this.key!, clientId: this.id!, documentId: docID, changePack: converter.toChangePack(reqPack), From 2018d90902a85964c4cfa590e6313776c3466b25 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Tue, 30 Jan 2024 00:04:27 +0900 Subject: [PATCH 45/48] Update CHANGELOG.md for v0.4.14 (#741) --- CHANGELOG.md | 5 ++++- package.json | 2 +- package.publish.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45c27f881..ea2a61a9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,15 +7,18 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [Unreleased] +## [0.4.14] - 2024-01-29 + ### Added -- Add design document for devtools extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/735 - Export LogLevel and setLogLevel @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/737 +- Add design document for devtools extension by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/735 ### Fixed - Follow up work after devtools mvp by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/734 - Fix invalid TreeChanges in concurrent Tree.Style by @hackerwins in https://github.com/yorkie-team/yorkie-js-sdk/pull/738 +- Restore interface changes due to server DB sharding by @sejongk https://github.com/yorkie-team/yorkie-js-sdk/pull/740 ## [0.4.13] - 2024-01-19 diff --git a/package.json b/package.json index d351990ad..f5d3cfb40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.14-rc", + "version": "0.4.14", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index d89b5f91a..a448857e0 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.14-rc", + "version": "0.4.14", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", From 87487c2faacb4d1058679a568e54273897509d2b Mon Sep 17 00:00:00 2001 From: LeeJongBeom <52884648+devleejb@users.noreply.github.com> Date: Tue, 30 Jan 2024 17:04:57 +0900 Subject: [PATCH 46/48] Fix invalid sync when editing multiple cursors in CodeMirror6 (#743) This commit addresses the synchronization issue that occurs when editing multiple cursors simultaneously in CodeMirror6. --- examples/vanilla-codemirror6/src/main.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/vanilla-codemirror6/src/main.ts b/examples/vanilla-codemirror6/src/main.ts index a45a2ceac..377b69bda 100644 --- a/examples/vanilla-codemirror6/src/main.ts +++ b/examples/vanilla-codemirror6/src/main.ts @@ -86,10 +86,13 @@ async function main() { if (tr.annotation(Transaction.remote)) { continue; } + let adj = 0; tr.changes.iterChanges((fromA, toA, _, __, inserted) => { + const insertText = inserted.toJSON().join('\n'); doc.update((root) => { - root.content.edit(fromA, toA, inserted.toJSON().join('\n')); + root.content.edit(fromA + adj, toA + adj, insertText); }, `update content byA ${client.getID()}`); + adj += insertText.length - (toA - fromA); }); } } From 156e2831ff2886d7d5238fba7a911778f5fdd3a6 Mon Sep 17 00:00:00 2001 From: Yourim Cha <81357083+chacha912@users.noreply.github.com> Date: Tue, 30 Jan 2024 17:23:34 +0900 Subject: [PATCH 47/48] Fix incorrect index returned when using posRangeToIndexRange (#742) The root cause of the issue was related to the use of getLastTimeTicket within posRangeToIndexRange(Ref: #611). To find nodes, the function findNodesAndSplitText was used, which includes a process to determine the position when inserting nodes, requiring a TimeTicket as a reference. However, for posRangeToIndexRange, which involves simple retrieval without node insertion, this logic was unnecessary. Consequently, This commit made modifications to exclude this specific logic. --------- Co-authored-by: Youngteac Hong --- src/document/crdt/tree.ts | 43 +++++++++++------------- src/document/json/tree.ts | 10 ++---- test/integration/tree_test.ts | 62 ++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 33 deletions(-) diff --git a/src/document/crdt/tree.ts b/src/document/crdt/tree.ts index 236f40419..766113bf4 100644 --- a/src/document/crdt/tree.ts +++ b/src/document/crdt/tree.ts @@ -691,10 +691,13 @@ export class CRDTTree extends CRDTGCElement { * The ids of the given `pos` are the ids of the node in the CRDT perspective. * This is different from `TreePos` which is a position of the tree in the * physical perspective. + * + * If `editedAt` is given, then it is used to find the appropriate left node + * for concurrent insertion. */ public findNodesAndSplitText( pos: CRDTTreePos, - editedAt: TimeTicket, + editedAt?: TimeTicket, ): [CRDTTreeNode, CRDTTreeNode] { // 01. Find the parent and left sibling node of the given position. const [parent, leftSibling] = pos.toTreeNodes(this); @@ -717,16 +720,18 @@ export class CRDTTree extends CRDTGCElement { // 04. Find the appropriate left node. If some nodes are inserted at the // same position concurrently, then we need to find the appropriate left // node. This is similar to RGA. - const allChildren = realParent.allChildren; - const index = isLeftMost ? 0 : allChildren.indexOf(leftNode) + 1; + if (editedAt) { + const allChildren = realParent.allChildren; + const index = isLeftMost ? 0 : allChildren.indexOf(leftNode) + 1; + + for (let i = index; i < allChildren.length; i++) { + const next = allChildren[i]; + if (!next.id.getCreatedAt().after(editedAt)) { + break; + } - for (let i = index; i < allChildren.length; i++) { - const next = allChildren[i]; - if (!next.id.getCreatedAt().after(editedAt)) { - break; + leftNode = next; } - - leftNode = next; } return [realParent, leftNode]; @@ -1247,28 +1252,18 @@ export class CRDTTree extends CRDTGCElement { */ public posRangeToPathRange( range: TreePosRange, - timeTicket: TimeTicket, ): [Array, Array] { - const [fromParent, fromLeft] = this.findNodesAndSplitText( - range[0], - timeTicket, - ); - const [toParent, toLeft] = this.findNodesAndSplitText(range[1], timeTicket); + const [fromParent, fromLeft] = this.findNodesAndSplitText(range[0]); + const [toParent, toLeft] = this.findNodesAndSplitText(range[1]); return [this.toPath(fromParent, fromLeft), this.toPath(toParent, toLeft)]; } /** * `posRangeToIndexRange` converts the given position range to the path range. */ - public posRangeToIndexRange( - range: TreePosRange, - timeTicket: TimeTicket, - ): [number, number] { - const [fromParent, fromLeft] = this.findNodesAndSplitText( - range[0], - timeTicket, - ); - const [toParent, toLeft] = this.findNodesAndSplitText(range[1], timeTicket); + public posRangeToIndexRange(range: TreePosRange): [number, number] { + const [fromParent, fromLeft] = this.findNodesAndSplitText(range[0]); + const [toParent, toLeft] = this.findNodesAndSplitText(range[1]); return [this.toIndex(fromParent, fromLeft), this.toIndex(toParent, toLeft)]; } diff --git a/src/document/json/tree.ts b/src/document/json/tree.ts index 8cd2ee4f8..d354a8689 100644 --- a/src/document/json/tree.ts +++ b/src/document/json/tree.ts @@ -613,10 +613,7 @@ export class Tree { CRDTTreePos.fromStruct(range[1]), ]; - return this.tree.posRangeToIndexRange( - posRange, - this.context.getLastTimeTicket(), - ); + return this.tree.posRangeToIndexRange(posRange); } /** @@ -636,9 +633,6 @@ export class Tree { CRDTTreePos.fromStruct(range[1]), ]; - return this.tree.posRangeToPathRange( - posRange, - this.context.getLastTimeTicket(), - ); + return this.tree.posRangeToPathRange(posRange); } } diff --git a/test/integration/tree_test.ts b/test/integration/tree_test.ts index f0ad7c2e5..527ad4c46 100644 --- a/test/integration/tree_test.ts +++ b/test/integration/tree_test.ts @@ -20,11 +20,12 @@ import { toDocKey, withTwoClientsAndDocuments, } from '@yorkie-js-sdk/test/integration/integration_helper'; +import { EventCollector } from '@yorkie-js-sdk/test/helper/helper'; import { TreeEditOpInfo, TreeStyleOpInfo, } from '@yorkie-js-sdk/src/document/operation/operation'; -import { Document } from '@yorkie-js-sdk/src/document/document'; +import { Document, DocEventType } from '@yorkie-js-sdk/src/document/document'; describe('Tree', () => { it('Can be created', function ({ task }) { @@ -612,6 +613,65 @@ describe('Tree', () => { range = tree.pathRangeToPosRange([[0], [1]]); assert.deepEqual(tree.posRangeToPathRange(range), [[0], [1]]); }); + + it('Should return correct range from index within doc.subscribe', async function ({ + task, + }) { + await withTwoClientsAndDocuments<{ t: Tree }>(async (c1, d1, c2, d2) => { + d1.update((root) => { + root.t = new Tree({ + type: 'doc', + children: [ + { type: 'p', children: [{ type: 'text', value: 'hello' }] }, + ], + }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

hello

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

hello

`); + + d1.update((root, presence) => { + root.t.edit(1, 1, { type: 'text', value: 'a' }); + const posSelection = root.t.indexRangeToPosRange([2, 2]); + presence.set({ selection: posSelection }); + }); + await c1.sync(); + await c2.sync(); + assert.equal(d1.getRoot().t.toXML(), /*html*/ `

ahello

`); + assert.equal(d2.getRoot().t.toXML(), /*html*/ `

ahello

`); + const { selection } = d1.getMyPresence(); + assert.deepEqual(d1.getRoot().t.posRangeToIndexRange(selection), [2, 2]); + + const eventCollector = new EventCollector<{ type: DocEventType }>(); + const unsub = d1.subscribe((event) => { + assert.deepEqual( + d1.getRoot().t.posRangeToIndexRange(selection), + [2, 2], + ); + eventCollector.add({ type: event.type }); + }); + d2.update((root) => { + root.t.edit(2, 2, { type: 'text', value: 'b' }); + }); + await c2.sync(); + await c1.sync(); + + assert.equal( + d1.getRoot().t.toXML(), + /*html*/ `

abhello

`, + ); + assert.equal( + d2.getRoot().t.toXML(), + /*html*/ `

abhello

`, + ); + + await eventCollector.waitAndVerifyNthEvent(1, { + type: DocEventType.RemoteChange, + }); + unsub(); + }, task.name); + }); }); describe('Tree.edit', function () { From e636b3e6f7a2a6120927b9a467e10c0853c55f9a Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Tue, 30 Jan 2024 17:42:40 +0900 Subject: [PATCH 48/48] Update CHANGELOG.md for v0.4.15-rc (#744) --- CHANGELOG.md | 5 +++++ package.json | 2 +- package.publish.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea2a61a9d..194178422 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and Yorkie JS SDK adheres to [Semantic Versioning](https://semver.org/spec/v2.0. ## [0.4.14] - 2024-01-29 +### Fixed + +- Fix invalid sync when editing multiple cursors in CodeMirror6 by @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/743 +- Fix incorrect index returned when using posRangeToIndexRange by @chacha912 in https://github.com/yorkie-team/yorkie-js-sdk/pull/742 + ### Added - Export LogLevel and setLogLevel @devleejb in https://github.com/yorkie-team/yorkie-js-sdk/pull/737 diff --git a/package.json b/package.json index f5d3cfb40..a3c7d36ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.14", + "version": "0.4.15-rc", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts", diff --git a/package.publish.json b/package.publish.json index a448857e0..3d48f6501 100644 --- a/package.publish.json +++ b/package.publish.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.4.14", + "version": "0.4.15-rc", "description": "Yorkie JS SDK", "main": "./dist/yorkie-js-sdk.js", "typings": "./dist/yorkie-js-sdk.d.ts",