import { Message } from '@bufbuild/protobuf'; import { Rule } from '@yorkie-js/schema'; import { Timestamp } from '@bufbuild/protobuf/wkt'; /** * `ActorID` is used to identify who is making changes to the document. * It is a hexadecimal string and should be generated by a unique value. */ export declare type ActorID = string; /** * `ActorID` is used to identify who is making changes to the document. * It is a hexadecimal string and should be generated by a unique value. */ declare type ActorID_2 = string; /** * `AddOpInfo` represents the information of the add operation. */ export declare type AddOpInfo = { type: 'add'; path: string; index: number; }; /** * `AddOpInfo` represents the information of the add operation. */ declare type AddOpInfo_2 = { type: 'add'; path: string; index: number; }; /** * `ArrayOpInfo` represents the OperationInfo for the JSONArray. */ export declare type ArrayOpInfo = AddOpInfo | RemoveOpInfo | MoveOpInfo | ArraySetOpInfo_2; /** * `ArrayOpInfo` represents the OperationInfo for the JSONArray. */ declare type ArrayOpInfo_2 = | AddOpInfo_2 | RemoveOpInfo_2 | MoveOpInfo_2 | ArraySetOpInfo; /** * `ArraySetOpInfo` represents the information of the array set operation. */ declare type ArraySetOpInfo = { type: 'array-set'; path: string; }; /** * `ArraySetOpInfo` represents the information of the array set operation. */ declare type ArraySetOpInfo_2 = { type: 'array-set'; path: string; }; /** * `Attachable` is an interface for resources that can be attached to a client. */ declare interface Attachable { /** * `getKey` returns the key of this resource. */ getKey(): string; /** * `getStatus` returns the status of this resource. */ getStatus(): ResourceStatus; /** * `setActor` sets the actor ID into this resource. */ setActor(actorID: ActorID): void; /** * `hasLocalChanges` returns whether this resource has local changes to be synchronized. * Returns true for Document when there are uncommitted changes. * Returns false for Presence as it is server-managed. */ hasLocalChanges(): boolean; /** * `publish` publishes an event to notify observers about changes in this resource. */ publish(event: unknown): void; } /** * `AttachChannelOptions` are user-settable options used when attaching channels. */ export declare interface AttachChannelOptions { /** * `syncMode` selects how the channel keeps presence in sync with the server. * Default is `SyncMode.Realtime`. * - `SyncMode.Realtime`: open a watch stream and run the heartbeat. Required * to receive broadcast events. * - `SyncMode.Polling`: heartbeat-only. No watch stream is opened. The * heartbeat refreshes TTL and brings the latest sessionCount. Recommended * for large channels where broadcast is not needed. * - `SyncMode.Manual`: no automatic activity. Caller must invoke `sync()`. */ syncMode?: SyncMode; /** * `channelHeartbeatInterval` overrides the heartbeat interval (ms) for * this attachment. If unset, the client-level default * (`ClientOptions.channelHeartbeatInterval`, default 5000 ms) applies * to both Realtime and Polling modes. */ channelHeartbeatInterval?: number; } /** * `AttachOptions` are user-settable options used when attaching documents. */ export declare interface AttachOptions { /** * `initialRoot` is the initial root of the document. It is used to * initialize the document. It is used when the fields are not set in the * document. */ initialRoot?: R; /** * `initialPresence` is the initial presence of the client. */ initialPresence?: P; /** * `syncMode` defines the synchronization mode of the document. */ syncMode?: SyncMode; /** * `documentPollInterval` (ms) — only used when `syncMode` is `Polling`. * Default: 3000. */ documentPollInterval?: number; /** * `schema` is the schema of the document. It is used to validate the * document. */ schema?: string; /** * `disableGC` declares that this attachment will not produce or consume * tombstones. The server skips minVV tracking and omits the response * VersionVector for this client. Use only with Counter or primitive * workloads; misuse on a document that uses Tree, Text, or Array * deletions leads to undefined GC behavior on this client. * * This option controls the wire contract with the server. It is * distinct from any local-only GC toggle on the Document. */ disableGC?: boolean; /** * `disablePresence` declares that this document does not use presence. * The first client to attach a document sets the persisted server-side * flag — subsequent attaches inherit the fixated value regardless of * what they pass. The client uses the server response to gate * `Document.update`'s presence emits (silently dropped) and skips the * initial `presence.set(opts.initialPresence)` emitted on attach. * * If omitted, the resolved value is `doc.isPresenceDisabled()` (the * value seeded from `DocumentOptions.disablePresence`, then overwritten * by any previous attach response on the same Document instance), with * a final fallback of `false`. */ disablePresence?: boolean; } declare interface AuthErrorEvent extends BaseDocEvent { type: DocEventType_2.AuthError; value: { reason: string; method: 'PushPull' | 'Watch'; }; } declare interface AuthErrorEvent_2 extends BaseDocEvent_2 { type: DocEventType.AuthError; value: { reason: string; method: 'PushPull' | 'Watch'; }; } /** * `AuthErrorEvent` represents an authentication error event. */ declare interface AuthErrorEvent_3 { /** * `type` is the type of the event. */ type: ChannelEventType.AuthError; /** * `reason` is the reason for the authentication error. */ reason: string; /** * `method` is the method that caused the authentication error. */ method: string; } declare type BaseArray = JSONArray | Array; /** * `BaseCounter` is an internal base that holds the shared state and * initialization logic for Counter and DedupCounter. Not exported. */ declare class BaseCounter { protected valueType: CounterType; protected value: number | bigint; protected context?: ChangeContext; protected counter?: CRDTCounter; constructor(valueType: CounterType, value: number | bigint); /** * `initialize` links this proxy to a ChangeContext and CRDTCounter. */ initialize(context: ChangeContext, counter: CRDTCounter): void; /** * `getID` returns the ID of this counter. */ getID(): TimeTicket; /** * `getValueType` returns the value type of this counter. */ getValueType(): CounterType; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `ensureInitialized` throws if this counter has not been initialized. */ protected ensureInitialized(): void; } declare interface BaseDocEvent { type: DocEventType_2; } declare interface BaseDocEvent_2 { type: DocEventType; } declare type BaseObject = JSONObject | T; declare interface BroadcastEvent { type: ChannelEventType.Broadcast; clientID: ActorID; topic: string; payload: Json; options?: BroadcastOptions; } /** * `BroadcastOptions` are the options for broadcasting a message. */ declare interface BroadcastOptions { /** * `error` is called when an error occurs. */ error?: (error: Error) => void; /** * `maxRetries` is the maximum number of retries. */ maxRetries?: number; } /** * `bytesToChangeID` creates a ChangeID from the given bytes. */ declare function bytesToChangeID(bytes: Uint8Array): ChangeID; /** * `bytesToHex` creates an hex string from the given byte array. */ declare function bytesToHex(bytes?: Uint8Array): string; /** * `bytesToObject` creates an JSONObject from the given byte array. */ declare function bytesToObject(bytes?: Uint8Array): CRDTObject; /** * `bytesToOperation` creates an Operation from the given bytes. */ declare function bytesToOperation(bytes: Uint8Array): Operation; /** * `bytesToSnapshot` creates a Snapshot from the given byte array. */ declare function bytesToSnapshot

(bytes?: Uint8Array): { root: CRDTObject; presences: Map; }; /** * `Change` represents a unit of modification in the document. */ export declare class Change

{ private id; private operations; private presenceChange?; private message?; constructor({ id, operations, presenceChange, message, }: { id: ChangeID; operations?: Array; presenceChange?: PresenceChange

; message?: string; }); /** * `create` creates a new instance of Change. */ static create

({ id, operations, presenceChange, message, }: { id: ChangeID; operations?: Array; presenceChange?: PresenceChange

; message?: string; }): Change

; /** * `getID` returns the ID of this change. */ getID(): ChangeID; /** * `getMessage` returns the message of this change. */ getMessage(): string | undefined; /** * `hasOperations` returns whether this change has operations or not. */ hasOperations(): boolean; /** * `getOperations` returns the operations of this change. */ getOperations(): Array; /** * `setActor` sets the given actor. */ setActor(actorID: ActorID): void; /** * `hasPresenceChange` returns whether this change has presence change or not. */ hasPresenceChange(): boolean; /** * `getPresenceChange` returns the presence change of this change. */ getPresenceChange(): PresenceChange

| undefined; /** * `execute` executes the operations of this change to the given root. */ execute(root: CRDTRoot, presences: Map, source: OpSource): { operations: Array; opInfos: Array; reverseOps: Array>; }; /** * `toTestString` returns a string containing the meta data of this change. */ toTestString(): string; /** * `toStruct` returns the structure of this change. */ toStruct(): ChangeStruct_2

; /** * `fromStruct` creates a instance of Change from the struct. */ static fromStruct

(struct: ChangeStruct_2

): Change

; } /** * @generated from message yorkie.v1.Change */ declare type Change_2 = Message<"yorkie.v1.Change"> & { /** * @generated from field: yorkie.v1.ChangeID id = 1; */ id?: ChangeID_2; /** * @generated from field: string message = 2; */ message: string; /** * @generated from field: repeated yorkie.v1.Operation operations = 3; */ operations: Operation_2[]; /** * @generated from field: yorkie.v1.PresenceChange presence_change = 4; */ presenceChange?: PresenceChange_2; }; /** * `ChangeApplyDetail` describes which change, and which operation of it, * could not be applied. `docKey` is unknown at the throw site inside the * change itself and is filled in by the document; `opIndex` and `operation` * are absent when the failure was not raised by a single operation. * * `operation` names the operation — its type and the element it targets — * and MUST NOT carry the operation's payload: this detail is spliced into a * message that is thrown to application code and logged at the default level, * so a payload there would publish plaintext document content. */ declare type ChangeApplyDetail = { docKey?: string; changeID: string; opIndex?: number; operation?: string; cause: unknown; }; /** * `ChangeApplyError` is thrown when a change cannot be applied to a document. * * It names the document, the change and the operation that failed, and keeps * the original error in `cause`. Without it the only signal is whatever the * operation threw, which says nothing about which change is stuck — and * because the checkpoint does not advance past a change that throws, the * server keeps redelivering it. */ export declare class ChangeApplyError extends YorkieError { name: string; readonly docKey?: string; readonly changeID: string; readonly opIndex?: number; readonly operation?: string; readonly cause: unknown; constructor(detail: ChangeApplyDetail); /** * `withDocKey` returns this error named with the given document key. The * change knows which operation failed but not which document it belongs * to, so the document adds its key as the error passes through. */ withDocKey(docKey: string): ChangeApplyError; } /** * `ChangeContext` is used to record the context of modification when editing * a document. Each time we add an operation, a new time ticket is issued. * Finally returns a Change after the modification has been completed. */ declare class ChangeContext

{ private prevID; private nextID; private delimiter; private message?; private root; private operations; private presenceChange?; /** * `previousPresence` stores the previous presence to be used for undoing * presence changes. */ private previousPresence; /** * `reversePresenceKeys` stores the keys of the presence to be used for undoing * presence changes. */ private reversePresenceKeys; constructor(prevID: ChangeID, root: CRDTRoot, presence: P, message?: string); /** * `create` creates a new instance of ChangeContext. */ static create

(prevID: ChangeID, root: CRDTRoot, presence: P, message?: string): ChangeContext

; /** * `push` pushes the given operation to this context. */ push(operation: Operation): void; /** * `registerElement` registers the given element to the root. */ registerElement(element: CRDTElement, parent: CRDTContainer): void; /** * `registerRemovedElement` register removed element for garbage collection. */ registerRemovedElement(deleted: CRDTElement): void; /** * `registerGCPair` registers the given pair to hash table. */ registerGCPair(pair: GCPair): void; /** * `getNextID` returns the next ID of this context. It will be set to the * document for the next change.returns the next ID of this context. */ getNextID(): ChangeID; /** * `toChange` creates a new instance of Change in this context. */ toChange(): Change

; /** * `isPresenceOnlyChange` returns whether this context is only for presence * change or not. */ isPresenceOnlyChange(): boolean; /** * `hasChange` returns whether this context has change or not. */ hasChange(): boolean; /** * `setPresenceChange` registers the presence change to this context. */ setPresenceChange(presenceChange: PresenceChange

): void; /** * `hasPresenceChange` returns whether a presence change was registered * during this context. Used by `Document.update` to detect a presence * emit when the document was attached with `disablePresence: true`. */ hasPresenceChange(): boolean; /** * `dropPresenceChange` clears any presence change registered during * this context. Used by `Document.update` to silently drop presence * emits on documents attached with `disablePresence: true`. After * dropping, the change carries only its operations (if any); when * the context was presence-only the resulting `hasChange()` returns * false and no `Change` is enqueued. */ dropPresenceChange(): void; /** * `setReversePresence` registers the previous presence to undo presence updates. */ setReversePresence(presence: Partial

, option?: { addToHistory: boolean; }): void; /** * `toReversePresence` returns the reverse presence of this context. */ getReversePresence(): Partial

| undefined; /** * `clearReversePresence` discards any reverse-presence keys recorded * during this context. Used by `Document.update` alongside * `dropPresenceChange` for documents attached with * `disablePresence: true`, so the dropped presence emit does not push * a no-op undo entry onto the history stack. */ clearReversePresence(): void; /** * `issueTimeTicket` creates a time ticket to be used to create a new operation. */ issueTimeTicket(): TimeTicket; /** * `getLastTimeTicket` returns the last time ticket issued in this context. */ getLastTimeTicket(): TimeTicket; /** * `acc` accumulates the given DataSize to Live size of the root. */ acc(diff: DataSize): void; /** * `accGC` accumulates the given DataSize to gc. See `CRDTRoot.accGC`. */ accGC(diff: DataSize): void; /** * `accMovedElement` books the size a move added to the moved element. See * `CRDTRoot.accMovedElement`. */ accMovedElement(element: CRDTElement, diff: DataSize): void; } /** * `ChangeID` is for identifying the Change. This is immutable. */ declare class ChangeID { private clientSeq; private serverSeq?; private actor; private lamport; private versionVector; constructor(clientSeq: number, lamport: bigint, actor: ActorID, vector: VersionVector, serverSeq?: bigint); /** * `hasClocks` returns true if this ID has logical clocks. */ hasClocks(): boolean; /** * `of` creates a new instance of ChangeID. */ static of(clientSeq: number, lamport: bigint, actor: ActorID, vector: VersionVector, serverSeq?: bigint): ChangeID; /** * `next` creates a next ID of this ID. */ next(excludeClocks?: boolean): ChangeID; /** * `syncClocks` syncs logical clocks with the given ID. If the given ID * doesn't have logical clocks, this ID is returned. */ syncClocks(other: ChangeID): ChangeID; /** * `syncLamport` advances the lamport clock against the given ID without * merging its version vector into the receiver's. It is the counterpart * of `syncClocks` for attachments that have opted out of GC participation * (see docs/design/disable-gc-on-attach.md in the server repo): the * receiver does not need other actors' entries in its VV because it * never produces or consumes tombstones, and dropping them keeps each * subsequent local Change's VV at O(1) instead of O(num_actors). * Lamport must still advance so that TimeTickets produced locally * remain ordered against remote operations. */ syncLamport(other: ChangeID): ChangeID; /** * `setClocks` sets the given clocks to this ID. This is used when the snapshot * is given from the server. */ setClocks(otherLamport: bigint, vector: VersionVector): ChangeID; /** * `createTimeTicket` creates a ticket of the given delimiter. */ createTimeTicket(delimiter: number): TimeTicket; /** * `setActor` sets the given actor. */ setActor(actorID: ActorID): ChangeID; /** * `setLamport` sets the given lamport clock. */ setLamport(lamport: bigint): ChangeID; /** * `setClientSeq` sets the given client sequence, leaving the logical clocks * alone. The counter and the clocks are independent positions: the counter * names this client's changes to the server, while the clocks order * operations against other actors. */ setClientSeq(clientSeq: number): ChangeID; /** * `setVersionVector` sets the given version vector. */ setVersionVector(versionVector: VersionVector): ChangeID; /** * `getClientSeq` returns the client sequence of this ID. */ getClientSeq(): number; /** * `getServerSeq` returns the server sequence of this ID. */ getServerSeq(): string; /** * `getLamport` returns the lamport clock of this ID. */ getLamport(): bigint; /** * `getLamportAsString` returns the lamport clock of this ID as a string. */ getLamportAsString(): string; /** * `getActorID` returns the actor of this ID. */ getActorID(): string; /** * `getVersionVector` returns the version vector of this ID. */ getVersionVector(): VersionVector; /** * `toTestString` returns a string containing the meta data of this ID. */ toTestString(): string; } /** * @generated from message yorkie.v1.ChangeID */ declare type ChangeID_2 = Message<"yorkie.v1.ChangeID"> & { /** * @generated from field: uint32 client_seq = 1; */ clientSeq: number; /** * @generated from field: int64 server_seq = 2; */ serverSeq: bigint; /** * @generated from field: int64 lamport = 3; */ lamport: bigint; /** * @generated from field: bytes actor_id = 4; */ actorId: Uint8Array; /** * @generated from field: yorkie.v1.VersionVector version_vector = 5; */ versionVector?: VersionVector_2; }; /** * `ChangeInfo` represents the modifications made during a document update * and the message passed. */ export declare interface ChangeInfo { message: string; operations: Array; actor: ActorID; clientSeq: number; serverSeq: string; } /** * `ChangeInfo` represents the modifications made during a document update * and the message passed. */ declare interface ChangeInfo_2 { message: string; operations: Array; actor: ActorID_2; clientSeq: number; serverSeq: string; } /** * `ChangePack` is a unit for delivering changes in a document to the remote. * */ declare class ChangePack

{ /** * `documentKey` is the key of the document. */ private documentKey; /** * `Checkpoint` is used to determine the client received changes. */ private checkpoint; /** * `isRemoved` is a flag that indicates whether the document is removed. */ private isRemoved; private changes; /** * `snapshot` is a byte array that encodes the document. */ private snapshot?; /** * `versionVector` is the version vector current document */ private versionVector?; /** * `epoch` is the document's compaction epoch. It is a bidirectional carrier: * server responses set it to the document's current epoch, and an attach/sync * request presents the client's last-known epoch so the server can detect a * stale-epoch mismatch after a force compaction. */ private epoch; constructor(key: string, checkpoint: Checkpoint, isRemoved: boolean, changes: Array>, versionVector?: VersionVector, snapshot?: Uint8Array, epoch?: bigint); /** * `create` creates a new instance of ChangePack. */ static create

(key: string, checkpoint: Checkpoint, isRemoved: boolean, changes: Array>, versionVector?: VersionVector, snapshot?: Uint8Array, epoch?: bigint): ChangePack

; /** * `getDocumentKey` returns the document key of this pack. */ getDocumentKey(): string; /** * `getCheckpoint` returns the checkpoint of this pack. */ getCheckpoint(): Checkpoint; /** * `getIsRemoved` returns the whether this document is removed. */ getIsRemoved(): boolean; /** * `getChanges` returns the changes of this pack. */ getChanges(): Array>; /** * `hasChanges` returns the whether this pack has changes or not. */ hasChanges(): boolean; /** * `getChangeSize` returns the size of changes this pack has. */ getChangeSize(): number; /** * `hasSnapshot` returns the whether this pack has a snapshot or not. */ hasSnapshot(): boolean; /** * `getSnapshot` returns the snapshot of this pack. */ getSnapshot(): Uint8Array | undefined; /** * `getVersionVector` returns the document's version vector of this pack */ getVersionVector(): VersionVector | undefined; /** * `getEpoch` returns the document's compaction epoch of this pack. */ getEpoch(): bigint; } /** * 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 */ declare type ChangePack_2 = Message<"yorkie.v1.ChangePack"> & { /** * @generated from field: string document_key = 1; */ documentKey: string; /** * @generated from field: yorkie.v1.Checkpoint checkpoint = 2; */ checkpoint?: Checkpoint_2; /** * @generated from field: bytes snapshot = 3; */ snapshot: Uint8Array; /** * @generated from field: repeated yorkie.v1.Change changes = 4; */ changes: Change_2[]; /** * deprecated * * @generated from field: yorkie.v1.TimeTicket min_synced_ticket = 5; */ minSyncedTicket?: TimeTicket_2; /** * @generated from field: bool is_removed = 6; */ isRemoved: boolean; /** * @generated from field: yorkie.v1.VersionVector version_vector = 7; */ versionVector?: VersionVector_2; /** * @generated from field: int64 epoch = 8; */ epoch: bigint; /** * capabilities is the negotiation channel for wire features a peer may not * understand. A server sets it on the pack it returns to advertise what it * supports; a client must treat absence as "unsupported" rather than as * "unknown", because a server that predates a feature cannot say so. * * It exists because a server does not store the bytes a client sent: it * re-encodes from its own domain model, so a field it does not know is * dropped from the stored change log and the push still succeeds. Without a * handshake a client cannot tell that its restore was silently downgraded to * an ordinary insert. Measured against a pinned v0.7.20 server. * * @generated from field: repeated string capabilities = 9; */ capabilities: string[]; }; /** * `ChangeStruct` represents the structure of Change. * This is used to serialize and deserialize Change. */ declare type ChangeStruct

= { changeID: string; message?: string; operations?: Array; presenceChange?: { type: PresenceChangeType; presence?: P; }; }; /** * `ChangeStruct` represents the structure of Change. * This is used to serialize and deserialize Change. */ declare type ChangeStruct_2

= { changeID: string; message?: string; operations?: Array; presenceChange?: { type: PresenceChangeType_2; presence?: P; }; }; /** * `Channel` represents a lightweight channel for presence and messaging. */ export declare class Channel implements Observable_2, Attachable { private key; private status; private actorID?; private sessionID?; private sessionCount; private seq; private eventStream; private eventStreamObserver; /** * @param key - the key of the channel. */ constructor(key: string); /** * `getKey` returns the key of this channel. */ getKey(): string; /** * `getFirstKeyPath` returns the first key path to the presence count. */ getFirstKeyPath(): string; /** * `getStatus` returns the status of this channel. */ getStatus(): ChannelStatus; /** * `applyStatus` applies the channel status into this channel. */ applyStatus(status: ChannelStatus): void; /** * `isAttached` returns whether this channel is attached or not. */ isAttached(): boolean; /** * `getActorID` returns the actor ID of this channel. */ getActorID(): ActorID | undefined; /** * `setActor` sets the actor ID into this channel. */ setActor(actorID: ActorID): void; /** * `getSessionID` returns the session ID from the server. */ getSessionID(): string | undefined; /** * `setSessionID` sets the session ID from the server. */ setSessionID(sessionID: string): void; /** * `getSessionCount` returns the current channel online session count value. */ getSessionCount(): number; /** * `updateSessionCount` updates the session count and sequence number if the sequence is newer. * Returns true if the count was updated, false if the update was ignored. */ updateSessionCount(sessionCount: number, seq: number): boolean; /** * `hasLocalChanges` returns whether this channel has local changes or not. * Channel is server-managed, so it always returns false. */ hasLocalChanges(): boolean; /** * `subscribe` registers a callback to subscribe to events on the channel. * The callback will be called when the broadcast event is received from the remote client. */ subscribe(type: 'broadcast', next: ChannelEventCallbackMap['broadcast']): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the channel. * The callback will be called when the local client sends a broadcast event. */ subscribe(type: 'local-broadcast', next: ChannelEventCallbackMap['local-broadcast']): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the channel. * The callback will be called when an authentication error occurs. */ subscribe(type: 'auth-error', next: ChannelEventCallbackMap['auth-error']): Unsubscribe; /** * `subscribe` registers a callback to subscribe to non-recoverable sync * (RefreshChannel) errors. Subsequent successful events on the channel * imply recovery — there is no separate "recovered" event. */ subscribe(type: 'sync-error', next: ChannelEventCallbackMap['sync-error']): Unsubscribe; /** * `subscribe` registers a callback to subscribe to presence events on the channel. * The callback will be called when the presence count changes. */ subscribe(type: 'presence', next: ChannelEventCallbackMap['presence']): Unsubscribe; /** * `subscribe` registers a callback to subscribe to all events on the channel. */ subscribe(type: 'all', next: ChannelEventCallbackMap['all']): Unsubscribe; /** * `subscribe` registers a callback to subscribe to broadcast events for a specific topic. * The callback will be called when a broadcast event with the matching topic is received. */ subscribe(topic: string, next: NextFn): Unsubscribe; /** * `subscribe` registers an observer for all channel events. * Returns an unsubscribe function. */ subscribe(arg1: NextFn): Unsubscribe; /** * `publish` publishes an event to all registered handlers. */ publish(event: ChannelEvent): void; /** * `broadcast` sends a message to all clients watching this channel. */ broadcast(topic: string, payload: any, options?: BroadcastOptions): void; private validateChannelKey; } /** * `ChannelEvent` represents an event that occurs in the channel. */ export declare type ChannelEvent = PresenceEvent_3 | BroadcastEvent | LocalBroadcastEvent | AuthErrorEvent_3 | SyncErrorEvent; /** * `ChannelEventCallbackMap` represents a map of event types to callbacks. */ declare type ChannelEventCallbackMap = { broadcast: NextFn; 'local-broadcast': NextFn; 'auth-error': NextFn; 'sync-error': NextFn; presence: NextFn; all: NextFn; }; /** * `ChannelEventType` represents the type of channel event. */ export declare enum ChannelEventType { /** * `Changed` means that the presence has changed. */ PresenceChanged = "presence-changed", /** * `Initialized` means that the presence watch has been initialized. */ Initialized = "initialized", /** * `Broadcast` means that a broadcast message has been received. */ Broadcast = "broadcast", /** * `LocalBroadcast` means that a broadcast message has been sent by the local client. */ LocalBroadcast = "local-broadcast", /** * `AuthError` means that an authentication error has occurred. */ AuthError = "auth-error", /** * `SyncError` means that a non-recoverable sync (RefreshChannel) error * occurred. Subscribers can use this to render an error state in the UI * without polling internal SDK state. The SDK still retries via its sync * loop, so subsequent successful events (PresenceChanged/Initialized) can * be treated as recovery. */ SyncError = "sync-error" } /** * `PresenceStatus` represents the status of the presence. */ export declare enum ChannelStatus { /** * `Detached` means that the presence is not attached to the client. */ Detached = "detached", /** * `Attached` means that the presence is attached to the client. */ Attached = "attached", /** * `Removed` means that the presence is removed. */ Removed = "removed" } /** * `Checkpoint` is used to determine the changes sent and received by the * client. This is immutable. * **/ declare class Checkpoint { private serverSeq; private clientSeq; constructor(serverSeq: bigint, clientSeq: number); /** * `of` creates a new instance of Checkpoint. */ static of(serverSeq: bigint, clientSeq: number): Checkpoint; /** * `increaseClientSeq` creates a new instance with increased client sequence. */ increaseClientSeq(inc: number): Checkpoint; /** * `forward` creates a new instance with the given checkpoint if it is * greater than the values of internal properties. */ forward(other: Checkpoint): Checkpoint; /** * `getServerSeqAsString` returns the server seq of this checkpoint as a * string. */ getServerSeqAsString(): string; /** * `getClientSeq` returns the client seq of this checkpoint. */ getClientSeq(): number; /** * `getServerSeq` returns the server seq of this checkpoint. */ getServerSeq(): bigint; /** * `equals` returns whether the given checkpoint is equal to this checkpoint * or not. */ equals(other: Checkpoint): boolean; /** * `toTestString` returns a string containing the meta data of this * checkpoint. */ toTestString(): string; } /** * @generated from message yorkie.v1.Checkpoint */ declare type Checkpoint_2 = Message<"yorkie.v1.Checkpoint"> & { /** * @generated from field: int64 server_seq = 1; */ serverSeq: bigint; /** * @generated from field: uint32 client_seq = 2; */ clientSeq: number; }; /** * `Client` is a normal client that can communicate with the server. * It has documents and sends changes of the documents in local * to the server to synchronize with other replicas in remote. */ export declare class Client { private id?; private actorID?; private key; private metadata; private status; private attachmentMap; private attachingDocs; private apiKey; private authTokenInjector?; private conditions; private syncLoopDuration; private reconnectStreamDelay; private retrySyncLoopDelay; private channelHeartbeatInterval; private deactivateOnUnload; private store?; private persistQueues; private persistStates; private sessionLock; private maxPersistBytes?; private persistDisabled; private maxPersistMillis?; private rpcClient; private setAuthToken; private taskQueue; private processing; private keepalive; private deactivating; /** * @param rpcAddr - the address of the RPC server. * @param opts - the options of the client. */ constructor(opts?: ClientOptions); /** * `activate` activates this client. That is, it registers itself to the server * and receives a unique ID from the server. The given ID is used to * distinguish different clients. */ activate(): Promise; /** * `deactivate` deactivates this client. * * @param options - If keepalive is true, the client will request deactivation * immediately using `fetch` with the `keepalive` option enabled. This is * useful for ensuring the deactivation request completes even if the page is * being unloaded, such as in `beforeunload` or `unload` event listeners. * If synchronous is true, the server will wait for all pending operations to * complete before deactivating. */ deactivate(options?: DeactivateOptions): Promise; /** * `has` checks if the given resource is attached to this client. * @param key - the key of the resource. * @returns true if the resource is attached to this client. */ has(key: Key): boolean; /** * `attach` attaches a Document or Channel to this client. * Overloaded to support both types. */ attach(resource: Document_2, opts?: AttachOptions): Promise>; /** * `attach` attaches the given channel to this client. The channel is * registered locally and the server is notified on the next RefreshChannel * heartbeat. */ attach(resource: Channel, opts?: AttachChannelOptions): Promise; /** * `attach` attaches the given document to this client. It tells the server that * this client will synchronize the given document. */ private attachDocument; /** * `detach` detaches a Document or Channel from this client. * Overloaded to support both types. */ detach(resource: Document_2, opts?: { keepalive?: boolean; }): Promise>; /** * `detach` detaches the given channel from this client. The detach is a * local cleanup; the server reclaims the session via TTL when heartbeats * stop. */ detach(resource: Channel): Promise; /** * `detach` detaches the given document from this client. It tells the * server that this client will no longer synchronize the given document. * * To collect garbage things like CRDT tombstones left on the document, all * the changes should be applied to other replicas before GC time. For this, * if the document is no longer used by this client, it should be detached. */ private detachDocument; /** * `attachChannel` attaches the given channel to this client. The channel is * registered locally and the server is notified on the next RefreshChannel * heartbeat. */ attachChannel(channel: Channel, opts?: AttachChannelOptions): Promise; /** * `detachChannel` detaches the given channel from this client. The detach * is a local cleanup; the server reclaims the session via TTL when * heartbeats stop. */ detachChannel(channel: Channel): Promise; /** * `changeSyncMode` changes the synchronization mode of the given document. */ changeSyncMode(doc: Document_2, syncMode: SyncMode): Promise>; /** * `changeSyncMode` changes the synchronization mode of the given channel. */ changeSyncMode(channel: Channel, syncMode: SyncMode): Promise; private changeDocumentSyncMode; /** * `assertValidChannelSyncMode` rejects sync modes that are not valid for * channels. `RealtimePushOnly` and `RealtimeSyncOff` are document-only. */ private assertValidChannelSyncMode; private changeChannelSyncMode; /** * `sync` pushes local changes of the attached documents to the server and * receives changes of the remote replica from the server then apply them to * local documents. * * For Channel in manual mode, it refreshes the TTL by sending a heartbeat. */ sync(doc?: Document_2): Promise>>; /** * `sync` refreshes the TTL of the given channel by sending a heartbeat. * This is used for manual mode channel. */ sync(channel: Channel): Promise; /** * `remove` removes the given document. */ remove(doc: Document_2): Promise; /** * `getID` returns the per-session id of this client. It is the wire * `clientId` used for RPC routing, not the actor stamped into document * changes. Use {@link getActorID} for the change author. */ getID(): string | undefined; /** * `getActorID` returns the actor stamped into this client's document * changes. On a server that supports stable actors it is the stable actor * derived from the project and client key (`ActivateClientResponse.actorId`); * otherwise it falls back to the per-session id. This is the actor a version * vector is keyed by, so tests and callers that reason about change * authorship or GC must use this, not {@link getID}. */ getActorID(): ActorID | undefined; /** * `getKey` returns a key of client. */ getKey(): string; /** * `storeKey` scopes a document key to this client's identity before it is * used as a `DocStore` key. The session lock is already scoped by * `apiKey/clientKey/docKey`; the store must match so a store shared across * identities (different apiKey/clientKey) cannot collide on the bare docKey * and hand one identity another's persisted envelope. Built through * {@link namespaceOf}, so the scoping is injective. */ private storeKey; /** * `persistToStore` saves the given bytes for a store key, serializing writes * per key so concurrent saves for the same document cannot interleave and * persist stale bytes (an earlier save resolving after a later one). Each key * chains onto its previous save; failures are logged, not thrown, and do not * break the chain for the next write. `onError` labels the log site. */ private persistToStore; /** * `snapshotWithinBudget` serializes a document for persistence and measures * what that cost. It answers `undefined` when the cost exceeds the client's * budget, having already latched persistence off for that document and * published {@link DocEventType.PersistDisabled}. * * Every snapshot write goes through here, which is the point: the budget is * only meaningful if nothing can serialize behind its back, and latching has * to tear down the subscription rather than merely skip a write — otherwise * each later edit keeps paying the serialization the budget exists to avoid. * The waste is bounded to the one measurement that discovers the problem. */ private snapshotWithinBudget; /** * `persistSnapshotOrPoison` writes a snapshot and re-poisons the log if that * write fails. * * Every snapshot write is also a *repair*: the callers reset the log * accounting and clear `poisoned` before it resolves, so that appends can * resume immediately. If the write then rejects, the store still holds the * old snapshot and whatever holed log went with it, while the client * believes the log is clean — the next append lands past the hole and the * following restore discards everything since the base snapshot. A * randomized fuzz over the transition space wedged 8 of 60 seeds this way. * * Re-poisoning makes the next edit try the snapshot again, which is the * behaviour the design's failure table already describes. */ private persistSnapshotOrPoison; /** * `appendToStore` appends one change for a store key, chained onto the same * per-key write queue `persistToStore` uses so an append can never overtake * the snapshot it belongs after. Failures are logged, not thrown: the store * may trail the document, and must never break the editing path. */ private appendToStore; /** * `saveMetaToStore` records the post-sync header, leaving the snapshot and * the change log intact. It does **not** drop acknowledged entries: the log * is the delta between the snapshot and current content as well as the queue * of un-pushed changes, and a push-ack brings the snapshot no further * forward, so trimming would leave that content in neither place. Only * compaction trims, by folding the entries into a new snapshot first. * * Deliberately not a snapshot: an online client syncs * constantly, and re-serializing per sync would reintroduce the cost the * incremental path removes. */ private saveMetaToStore; /** * `removeFromStore` clears the persisted envelope for a document key, scoped * to this client's identity. A flaky store must not abort the attach/recover * path, so a rejection is logged rather than thrown. */ private removeFromStore; /** * `emitLocalChangesDropped` surfaces an app-visible data-loss event carrying * the un-pushed local changes the offline-persistence layer had to discard. * The design mandates raising this instead of silently dropping edits when a * persisted envelope cannot be reconciled with the server (a stale-epoch * re-anchor, a server-side purge, or a store reused under a different actor). */ private emitLocalChangesDropped; /** * `isActive` checks if the client is active. */ isActive(): boolean; /** * `getStatus` returns the status of this client. */ getStatus(): ClientStatus; /** * `getCondition` returns the condition of this client. */ getCondition(condition: ClientCondition): boolean; /** * `createRevision` creates a new revision for the given document. */ createRevision(doc: Document_2, label: string, description?: string): Promise; /** * `listRevisions` lists all revisions for the given document. */ listRevisions(doc: Document_2, options?: { pageSize?: number; offset?: number; isForward?: boolean; }): Promise>; /** * `getRevision` retrieves a specific revision by its ID with full snapshot data. */ getRevision(doc: Document_2, revisionID: string): Promise; /** * `restoreRevision` restores the document to the given revision. */ restoreRevision(doc: Document_2, revisionId: string): Promise; /** * `peekChannel` reads the current session count of a channel without * creating a session on the server. Use this when the caller only needs * to display the count (e.g. "N people writing") without contributing to * it and without receiving broadcasts. * * Unlike `attach({ readOnly: true })`, this does not occupy a `Session` * entry on the server, does not generate heartbeat RPCs, and does not * subscribe to channel events. Polling is the caller's responsibility. */ peekChannel(channelKey: string): Promise; /** * `broadcast` broadcasts the given payload to the given topic. */ broadcast(key: Key, topic: string, payload: any, options?: BroadcastOptions): Promise; /** * `runSyncLoop` runs the sync loop. The sync loop pushes local changes to * the server and pulls remote changes from the server. */ private runSyncLoop; /** * `runWatchLoop` runs the watch loop for the given resource (Document or Channel). * The watch loop listens to the events of the given resource from the server. */ private runWatchLoop; /* Excluded from this release type: createDocumentWatchStream */ /* Excluded from this release type: createChannelWatchStream */ /* Excluded from this release type: handleWatchChannelResponse */ private handleWatchDocumentResponse; private deactivateInternal; private detachInternal; private syncInternal; /** * `handleConnectError` handles the given error. If the given error can be * retried after handling, it returns true. */ private handleConnectError; /** * `enqueueTask` enqueues the given task to the task queue. */ private enqueueTask; /** * `processNext` processes the next task in the task queue. This method is * part of enqueueTask. */ private processNext; } /** * `Client` represents a client value in devtools. */ declare type Client_2 = { clientID: string; presence: Json_2; }; /** * `ClientCondition` represents the condition of the client. */ export declare enum ClientCondition { /** * `SyncLoop` is a key of the sync loop condition. */ SyncLoop = "SyncLoop", /** * `WatchLoop` is a key of the watch loop condition. */ WatchLoop = "WatchLoop" } export declare interface ClientOptions { /** * `rpcAddr` is the address of the RPC server. It is used to connect to * the server. */ rpcAddr?: string; /** * `key` is the client key. It is used to identify the client. * If not set, a random key is generated. * * That random default is minted per `Client` instance, so it differs on every * launch. **Offline persistence requires a stable key**: the server derives * the actor stamped into every change from the project and this key, and it * also scopes the {@link ClientOptions.store} keys * (`apiKey/clientKey/docKey`). A new key therefore does not address the * previous launch's entries at all — the restore finds nothing, the un-pushed * edits are lost *silently* (no {@link DocEventType.LocalChangesDropped} * event: the `actor-mismatch` guard in * {@link Document.restoreFromBytes} only fires when the *same* store key is * reached under a different actor), and the previous namespace is orphaned. * `DocStore` exposes no enumeration or prune, so nothing can reclaim those * entries afterwards and a durable backend grows without bound, one dead * namespace per launch. * * An app setting `store` must therefore pass a key it persists itself and * reuses on the next launch. Make it an **opaque random value the app mints * once** — `crypto.randomUUID()` kept in local storage, say — scoped to the * signed-in user and cleared on sign-out. Do **not** derive it from a user * id, a device id, an email, or anything else guessable or shared: * * - The key is an identifier, not a credential. It is sent verbatim in * `ActivateClientRequest.client_key` and nothing proves the caller owns it, * so a guessable key lets another client of the same project activate under * the same derived actor and attribute changes to it. * - A key shared between users of one browser (a device id) gives them one * store namespace. `attach` loads and rehydrates the persisted bytes * locally *before* the attach RPC, so the previous user's document content * and un-pushed edits would surface in the next user's session ahead of any * server authorization. */ key?: string; /** * `apiKey` is the API key of the project. It is used to identify the project. * If not set, API key of the default project is used. */ apiKey?: string; /** * `metadata` is the metadata of the client. It is used to store additional * information about the client. */ metadata?: Record; /** * `authTokenInjector` is a function that provides a token for the auth webhook. * When the webhook response status code is 401, this function is called to refresh the token. * The `reason` parameter is the reason from the webhook response. */ authTokenInjector?: (reason?: string) => Promise; /** * `syncLoopDuration` is the duration of the sync loop. After each sync loop, * the client waits for the duration to next sync. The default value is * `50`(ms). */ syncLoopDuration?: number; /** * `retrySyncLoopDelay` is the delay of the retry sync loop. If the sync loop * fails, the client waits for the delay to retry the sync loop. The default * value is `1000`(ms). */ retrySyncLoopDelay?: number; /** * `reconnectStreamDelay` is the delay of the reconnect stream. If the stream * is disconnected, the client waits for the delay to reconnect the stream. The * default value is `1000`(ms). */ reconnectStreamDelay?: number; /** * `channelHeartbeatInterval` is the interval of the channel heartbeat (ms). * The client sends a `RefreshChannel` heartbeat to refresh the channel * session TTL. The default value is `5000` (ms) — co-tuned to the server's * `ChannelSessionTTL` (15 s) at TTL/3. Values larger than the server TTL * risk premature session expiry. */ channelHeartbeatInterval?: number; /** * `userAgent` is the user agent of the client. It is used to identify the * client. */ userAgent?: string; /** * `useGrpcWebTransport` determines the transport protocol. * If true, uses gRPC-Web transport for backward compatibility. * If false (default), uses Connect Protocol transport. */ useGrpcWebTransport?: boolean; /** * `deactivateOnUnload` controls whether the client registers a * `beforeunload` listener during `activate()` that deactivates the client * when the page is unloaded. The default value is `true`. * * Setting this to `false` skips the listener registration. This is useful * for apps that don't need GC or presence cleanup on unload (for example, * `disableGC` documents without collaboration): the unload-time * deactivate becomes pure overhead and its `fetch({ keepalive: true })` * request can reject mid-flight during hard navigation, surfacing as an * unhandled `[unknown]` `ConnectError`. The server reaps the stale * client after its `clientDeactivateThreshold`, so opting out is safe. */ deactivateOnUnload?: boolean; /** * `store` is a pluggable persistence backend for offline document state. * When set, the client writes one base snapshot at attach and then **appends * each local change**, so recording an edit costs the size of that edit * rather than of the whole document. The log is compacted back into a * snapshot once it grows large relative to it. A sync that only acks a push * writes the small `meta` header; a sync that pulls content writes a * snapshot, because the log carries local changes only. On `attach` the * document is rehydrated from the snapshot and the log is replayed over it, * so un-pushed local changes survive a reload. The * restored checkpoint is presented in the attach ChangePack so the server * seeds the client's document sequence from it and re-accepts the re-pushed * local changes. When unset (the default), no persistence happens. * * For offline persistence you also want `deactivateOnUnload: false`: the * default `true` deactivates the client on page unload, which detaches * documents server-side and defeats the point of resuming un-pushed local * changes on the next load. Setting `store` therefore auto-defaults * `deactivateOnUnload` to `false`; pass it explicitly to override. * * You **must** also set {@link ClientOptions.key} to an opaque random value * the app mints once and reuses across launches. Both the store keys and the * actor recovery is keyed by are derived from it, and the default is a fresh * random key per `Client`, so leaving it unset means every restart silently * loses every un-pushed change and orphans the previous launch's entries. * This cannot be defaulted correctly — only the app knows what identity * should outlive the process — so the client warns rather than guessing. See * {@link ClientOptions.key} for why the value must not be a user id, a device * id, or anything else guessable or shared between users of one browser. */ store?: DocStore; /** * `sessionLock` is the single-active-session guard used only on the offline * persistence path (when `store` is set). Offline persistence derives a * stable actor from the app's clientKey, so two tabs of the same app+user * share it; two live tabs would share one server checkpoint and mint * colliding `clientSeq` values — silent edit loss. On `attach` the client * acquires a lock keyed by `apiKey/clientKey/docKey` and holds it for the * attachment lifetime; if it is already held (another tab) the attach fails * fast. The default {@link WebLocksSessionLock} uses the Web Locks API and is * a no-op in non-browser runtimes; inject a fake for testing. Ignored when * `store` is unset (non-persistence clients keep today's behavior). */ sessionLock?: SessionLock; /** * `maxPersistBytes` caps the size of a snapshot this client is willing to * write. A document whose snapshot exceeds it stops being persisted and a * {@link DocEventType.PersistDisabled} event is published; editing is * unaffected. * * Only snapshots are measured. Appends are a few hundred bytes regardless of * document size, so they need no budget — the budget exists for the one * operation whose cost scales with the document. * * Unset means no limit. */ maxPersistBytes?: number; /** * `maxPersistMillis` caps how long serializing a snapshot may block the main * thread before this client gives up persisting the document. Same effect * and same event as {@link maxPersistBytes}. Unset means no limit. */ maxPersistMillis?: number; } /** * `ClientStatus` represents the status of the client. */ export declare enum ClientStatus { /** * `Deactivated` means that the client is not activated. It is the initial * status of the client. If the client is deactivated, all `Document`s of the * client are also not used. */ Deactivated = "deactivated", /** * `Activated` means that the client is activated. If the client is activated, * all `Document`s of the client are also ready to be used. */ Activated = "activated" } export declare enum Code { Ok = "ok", ErrClientNotActivated = "ErrClientNotActivated", ErrClientNotFound = "ErrClientNotFound", ErrUnimplemented = "ErrUnimplemented", ErrInvalidType = "ErrInvalidType", ErrDummy = "ErrDummy", ErrNotAttached = "ErrNotAttached", ErrNotDetached = "ErrNotDetached", ErrAlreadyAttached = "ErrAlreadyAttached", ErrSessionNotFound = "ErrSessionNotFound", ErrDocumentRemoved = "ErrDocumentRemoved", ErrDocumentSizeExceedsLimit = "ErrDocumentSizeExceedsLimit", ErrDocumentSchemaValidationFailed = "ErrDocumentSchemaValidationFailed", ErrInvalidObjectKey = "ErrInvalidObjectKey", ErrInvalidArgument = "ErrInvalidArgument", ErrNotInitialized = "ErrNotInitialized", ErrNotReady = "ErrNotReady", ErrRefused = "ErrRefused", ErrContextNotProvided = "ErrContextNotProvided", ErrPermissionDenied = "ErrPermissionDenied", ErrUnauthenticated = "ErrUnauthenticated", ErrTooManySubscribers = "ErrTooManySubscribers", ErrTooManyAttachments = "ErrTooManyAttachments", ErrEpochMismatch = "ErrEpochMismatch", ErrDocumentOpenElsewhere = "ErrDocumentOpenElsewhere", ErrChangeApplyFailed = "ErrChangeApplyFailed" } declare type Comparator = (keyA: K, keyB: K) => number; export declare type CompleteFn = () => void; /** * `ConnectionChangedEvent` is an event that occurs when the stream connection state changes. */ export declare interface ConnectionChangedEvent extends BaseDocEvent_2 { type: DocEventType.ConnectionChanged; value: StreamConnectionStatus; } /** * `ConnectionChangedEvent` is an event that occurs when the stream connection state changes. */ declare interface ConnectionChangedEvent_2 extends BaseDocEvent { type: DocEventType_2.ConnectionChanged; value: StreamConnectionStatus_2; } /** * `ContainerValue` represents the result of `Array.toJSForTest()` and * `Object.toJSForTest()`. */ declare type ContainerValue = { [key: string]: JSONElement_2; }; /** * `converter` is a converter that converts the given model to protobuf format. * is also used to convert models to bytes and vice versa. */ export declare const converter: { fromPresence: typeof fromPresence; toChangePack: typeof toChangePack; fromChangePack: typeof fromChangePack; fromChanges: typeof fromChanges; toTreeNodes: typeof toTreeNodes; fromTreeNodes: typeof fromTreeNodes; objectToBytes: typeof objectToBytes; bytesToObject: typeof bytesToObject; bytesToSnapshot: typeof bytesToSnapshot; snapshotToBytes: typeof snapshotToBytes; bytesToHex: typeof bytesToHex; hexToBytes: typeof hexToBytes; toHexString: typeof toHexString; toUint8Array: typeof toUint8Array; toOperation: typeof toOperation; toChangeID: typeof toChangeID; bytesToChangeID: typeof bytesToChangeID; bytesToOperation: typeof bytesToOperation; versionVectorToHex: typeof versionVectorToHex; hexToVersionVector: typeof hexToVersionVector; fromSchemaRules: typeof fromSchemaRules; toRevisionSummary: typeof toRevisionSummary; changeIDToBinary: (changeID: ChangeID) => Uint8Array; operationToBinary: (op: Operation) => Uint8Array; }; /** * `Counter` is a numeric counter that supports `increase()`. * For counting unique actors, use `DedupCounter` instead. * * ```typescript * // Type is inferred from value: * root.count = new Counter(0); // Int * root.count = new Counter(0n); // Long * ``` */ export declare class Counter extends BaseCounter { constructor(value: number | bigint); /** * `getValue` returns the value of this counter. */ getValue(): number | bigint; /** * `increase` increases numeric data. */ increase(v: number | bigint): Counter; } /** * `CounterOpInfo` represents the OperationInfo for the yorkie.Counter. */ export declare type CounterOpInfo = IncreaseOpInfo; /** * `CounterOpInfo` represents the OperationInfo for the yorkie.Counter. */ declare type CounterOpInfo_2 = IncreaseOpInfo_2; export declare enum CounterType { Int = 0, Long = 1, IntDedup = 2 } export declare type CounterValue = number | bigint; declare type CounterValue_2 = number | bigint; /** * * `CRDTContainer` represents CRDTArray or CRDtObject. */ declare abstract class CRDTContainer extends CRDTElement { constructor(createdAt: TimeTicket); /** * `subPathOf` returns the sub path of the given element. */ abstract subPathOf(createdAt: TimeTicket): string | undefined; abstract purge(element: CRDTElement): void; /** * `purgeBarrierAt` is the element-side form of `GCParent.purgeBarrierAt`, * for a container whose purge unlinks a node of its RGA order (`CRDTArray`). */ purgeBarrierAt?(element: CRDTElement): TimeTicket | undefined; abstract delete(createdAt: TimeTicket, executedAt: TimeTicket): 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; } /** * `CRDTCounter` is a CRDT implementation of a counter. It is used to represent * a number that can be incremented or decremented. */ declare class CRDTCounter extends CRDTElement { private valueType; private value; private hll?; constructor(valueType: CounterType, value: CounterValue, createdAt: TimeTicket); /** * `of` creates a new instance of Counter. */ static create(valueType: CounterType, value: CounterValue, createdAt: TimeTicket): CRDTCounter; /** * `valueFromBytes` parses the given bytes into value. */ static valueFromBytes(counterType: CounterType, bytes: Uint8Array): CounterValue; /** * `getDataSize` returns the data usage of this element. */ getDataSize(): DataSize; /** * `toJSON` returns the JSON encoding of the value. */ toJSON(): string; /** * `toSortedJSON` returns the sorted JSON encoding of the value. */ toSortedJSON(): string; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `deepcopy` copies itself deeply. */ deepcopy(): CRDTCounter; /** * `getType` returns the type of the value. */ getType(): CounterType; /** * `getCounterType` returns counter type of given value. */ static getCounterType(value: CounterValue): CounterType | undefined; /** * `isSupport` check if there is a counter type of given value. */ static isSupport(value: CounterValue): boolean; /** * `isInteger` checks if the num is integer. */ static isInteger(num: number): boolean; /** * `isNumericType` check numeric type by JSONCounter. */ isNumericType(): boolean; /** * `getValueType` get counter value type. */ getValueType(): CounterType; /** * `getValue` get counter value. */ getValue(): CounterValue; /** * `toBytes` creates an array representing the value. */ toBytes(): Uint8Array; /** * `isDedup` returns whether dedup mode is enabled (derived from ValueType). */ isDedup(): boolean; /** * `increaseDedup` increases the counter using HLL-based dedup. * Only updates the value if the actor is new (not seen before). */ increaseDedup(v: Primitive, actor: string): CRDTCounter; /** * `hllBytes` returns the HLL register bytes, or undefined if not in dedup mode. */ hllBytes(): Uint8Array | undefined; /** * `restoreHLL` restores the HLL state from serialized bytes, returning * whether the bytes were accepted. A rejected payload leaves both the HLL * and the value as they were, because the value it would recompute is * derived from the registers and a malformed payload does not describe a * cardinality. */ restoreHLL(data: Uint8Array): boolean; /** * `recomputeValue` updates the counter value from the HLL cardinality estimate. */ private recomputeValue; /** * `increase` increases numeric data. * Dedup counters must use increaseDedup() instead. */ increase(v: Primitive): CRDTCounter; } /** * `CRDTElement` represents an element that has `TimeTicket`s. */ declare abstract class CRDTElement { private createdAt; private movedAt?; private removedAt?; constructor(createdAt: TimeTicket); /** * `getCreatedAt` returns the creation time of this element. */ getCreatedAt(): TimeTicket; /** * `getID` returns the creation time of this element. */ getID(): TimeTicket; /** * `getMovedAt` returns the move time of this element. */ getMovedAt(): TimeTicket | undefined; /** * `getRemovedAt` returns the removal time of this element. */ getRemovedAt(): TimeTicket | undefined; /** * `getPositionedAt` returns the time of this element when it was positioned * in the document by undo/redo or move operation. */ getPositionedAt(): TimeTicket; /** * `setCreatedAt` sets the creation time of this element manually. */ setCreatedAt(createdAt: TimeTicket): void; /** * `setMovedAt` sets the move time of this element. */ setMovedAt(movedAt?: TimeTicket): boolean; /** * `setRemovedAt` sets the remove time of this element. */ setRemovedAt(removedAt?: TimeTicket): void; /** * `remove` removes this element. */ remove(removedAt?: TimeTicket): boolean; /** * `isRemoved` check if this element was removed. */ isRemoved(): boolean; /** * `getMetaUsage` returns the meta usage of this element. */ getMetaUsage(): number; /** * `getDataSize` returns the data usage of this element. */ abstract getDataSize(): DataSize; abstract toJSON(): string; abstract toSortedJSON(): string; abstract toJSForTest(): Devtools.JSONElement; abstract deepcopy(): CRDTElement; } /** * `CRDTElementPair` is a structure that represents a pair of element and its * parent. It is used to find the parent of a specific element to perform * garbage collection and to find the path of a specific element. */ declare interface CRDTElementPair { element: CRDTElement; parent?: CRDTContainer; } /** * `CRDTObject` represents an object data type, but unlike regular JSON, * it has `TimeTicket`s which are created by logical clock. * */ declare class CRDTObject extends CRDTContainer { private memberNodes; constructor(createdAt: TimeTicket, memberNodes: ElementRHT); /** * `create` creates a new instance of CRDTObject. */ static create(createdAt: TimeTicket, value?: { [key: string]: CRDTElement; }): CRDTObject; /** * `subPathOf` returns the sub path of the given element. */ subPathOf(createdAt: TimeTicket): string | undefined; /** * `purge` physically purges the given element. */ purge(value: CRDTElement): void; /** * `set` sets the given element of the given key. */ set(key: string, value: CRDTElement, executedAt: TimeTicket): CRDTElement | undefined; /** * `delete` deletes the element of the given key. */ delete(createdAt: TimeTicket, executedAt: TimeTicket): CRDTElement; /** * `deleteByKey` deletes the element of the given key and execution time. */ deleteByKey(key: string, executedAt: TimeTicket): CRDTElement | undefined; /** * `get` returns the value of the given key. */ get(key: string): CRDTElement | undefined; /** * `getByID` returns the element of the given createAt. */ getByID(createdAt: TimeTicket): CRDTElement | undefined; /** * `has` returns whether the element exists of the given key or not. */ has(key: string): boolean; /** * `getDataSize` returns the data usage of this element. */ getDataSize(): DataSize; /** * `toJSON` returns the JSON encoding of this object. */ toJSON(): string; /** * `toJS` returns the JavaScript object of this object. */ toJS(): any; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `getKeys` returns array of keys in this object. */ getKeys(): Array; /** * `toSortedJSON` returns the sorted JSON encoding of this object. */ toSortedJSON(): string; /** * `getRHT` RHTNodes returns the RHTPQMap nodes. */ getRHT(): ElementRHT; /** * `deepcopy` copies itself deeply. */ deepcopy(): CRDTObject; /** * `getDescendants` returns the descendants of this object by traversing. */ getDescendants(callback: (elem: CRDTElement, parent: CRDTContainer) => boolean): void; /** * `[Symbol.iterator]` returns an iterator for the entries in this object. */ [Symbol.iterator](): IterableIterator<[string, CRDTElement]>; } /** * `CRDTRoot` is a structure that represents the root. It has a hash table of * all elements to find a specific element when applying remote changes * received from server. * * Every element has a unique `TimeTicket` at creation, which allows us to find * a particular element. */ declare class CRDTRoot { /** * `rootObject` is the root object of the document. */ private rootObject; /** * `elementPairMapByCreatedAt` is a hash table that maps the creation time of * an element to the element itself and its parent. */ private elementPairMapByCreatedAt; /** * `gcElementSetByCreatedAt` is a hash set that contains the creation * time of the removed element. It is used to find the removed element when * executing garbage collection. */ private gcElementSetByCreatedAt; /** * `sizeInGC` maps every registered element whose size counts toward * `docSize.gc` rather than `docSize.live` to the exact amount * charged. Each element's size belongs * to exactly one of the two, and an element reaches gc by more routes than it * has removals: it can be removed itself, or be a descendant of a removed * container. Recording the amount rather than a flag keeps the two sides * symmetric even though `getDataSize` is not stable over an element's * lifetime -- it grows by a ticket the moment `removedAt` is set, which can * happen after the size has already moved. * * It is keyed by the element, not by its createdAt. A createdAt is meant to * name one element, but it does not for the whole of a document's life: undo * restores a `deepcopy` of a removed element, and the copy keeps the * original's createdAt while the original is still a tombstone. Undoing an * array removal reissues a ticket for the restored container alone, so its * members come back aliasing the tombstoned ones outright. One slot per * createdAt cannot describe both: whichever is charged last displaces the * other, and collecting the displaced one then takes a size out of * `docSize.live` that live was never holding -- which is how docSize goes * negative. One slot per element has room for both. * * A zero size is not the same as no record. It says this element has been * released: charged to neither side, because its subtree was orphaned by a * restore and nothing will ever collect it. Anything that later charges it * again has to know live is not the side to take it from. * * It is a `WeakMap` because a released element's record has no retirement of * its own. `release` writes the zero record for a tombstone the restore * orphaned, and that tombstone is dropped from `gcElementSetByCreatedAt` in * the same breath -- so nothing collects it, nothing deregisters it, and a * strong map would hold both the record and the element for the life of the * document, growing by one subtree per remove/undo. The record is only ever * reached through the element it is keyed by -- this map is never iterated * and never counted -- so its useful lifetime IS the element's: the zero * marker stands for exactly as long as the tombstone stays addressable, * which is the only window in which `moveSizeToGC` or `accMovedElement` can * consult it. */ private sizeInGC; /** * `gcPairMap` is a hash table of the registered GC pairs, keyed by both of * a pair's ends. * * The child's IDString alone is not unique document-wide. An RHTNode is * identified by (updatedAt, key), and a split deep-copies the attributes of * the node it splits -- tombstones included, because the copy has to reject * the same stale styles the original does. The copy is therefore a distinct * piece of garbage wearing the original's id. Keying on the child alone made * the two collide, and since `registerGCPair` reads a second registration * under a known key as an un-registration, the second tombstone cancelled * the first instead of joining it. * * The parent is the discriminator because it is what `purge` is called on: * two pairs that share a parent and a child id name the same collectable * thing, two that differ in either do not. */ private gcPairMap; /** * `gcParentIDs` numbers the GC parents this root has seen, so a pair's key * can name its parent. No GC parent carries an identifier of its own, and * minting one per root is enough: a key never has to mean anything outside * the root that made it, since registration, lookup and purge all happen * within one. Weak so a parent the document has dropped is not held alive * by its number. */ private gcParentIDs; private nextGCParentID; /** * `docSize` is a structure that represents the size of the document. */ private docSize; constructor(rootObject: CRDTObject); /** * `create` creates a new instance of Root. */ static create(): CRDTRoot; /** * `findByCreatedAt` returns the element of given creation time. */ findByCreatedAt(createdAt: TimeTicket): CRDTElement | undefined; /** * `findElementPairByCreatedAt` returns the element and parent pair * of given creation time. */ findElementPairByCreatedAt(createdAt: TimeTicket): CRDTElementPair | undefined; /** * `createSubPaths` creates an array of the sub paths for the given element. */ createSubPaths(createdAt: TimeTicket): Array; /** * `createPath` creates path of the given element. */ createPath(createdAt: TimeTicket): string; /** * `registerElement` registers the given element and its descendants to hash table. */ registerElement(element: CRDTElement, parent?: CRDTContainer): void; /** * `registerInternalGCPairs` books the tombstones the given element and its * descendant elements carry inside themselves into gc. Freshly created * content has none, so this costs one walk of the registered subtree and no * registration in the common case. */ private registerInternalGCPairs; /** * `registerLive` registers the given element and its descendants to the pair * map, and charges `docSize.live` for each. */ private registerLive; /** * `adoptTombstones` books every element of the given subtree that already * carries a `removedAt` into gc. */ private adoptTombstones; /** * `deregisterElement` deregister the given element and its descendants from hash table. */ deregisterElement(element: CRDTElement): number; /** * `registerRemovedElement` registers the given element to the hash set. */ registerRemovedElement(element: CRDTElement): void; /** * `adoptRemovedElement` books an element that was already tombstoned when it * was registered, and its descendants, into gc. It is * `registerRemovedElement` without the ticket refund: the size just charged * to live already included the `removedAt` ticket, so live has nothing to get * back. */ private adoptRemovedElement; /** * `moveDescendantsToGC` moves the size of every descendant of the given * element from live to gc. * * NOTE(hackerwins): registerElement books a container and every descendant * into live, and deregisterElement subtracts both when the tombstone is * collected. Removing a container therefore has to move its descendants as * well: booking only the container itself would strand their size in live * forever and drive gc negative once the collection subtracted them. */ private moveDescendantsToGC; /** * `moveSizeToGC` moves the size of the given element from live to gc, and * reports whether it moved a size live was holding. A size already charged to * gc for this same element -- because it was removed before, because a * container above it was, or because a restore released it -- only has its * charge topped up: getDataSize grows by a ticket when removedAt is set, * which can happen after the move. * * Another element sharing this createdAt has a charge of its own, and it is * not this one's: this element is still in live and moves in full. */ private moveSizeToGC; /** * `unregisterRemovedElementPair` drops the collection entry registered under * the given createdAt, if there is one, and releases the charge it holds. It * reports whether an entry was dropped. * * It is the narrow counterpart of `registerRemovedElement`, for the one * caller that has to retire a tombstone without collecting it: a `Set` that * restores an element under a createdAt a tombstone already answers to. * `ElementRHT.set` has by then re-pointed `nodeMapByCreatedAt` at the * restored copy, so the entry the removal left behind now resolves, through * that index, to live data -- and collection would purge it. * * Deliberately narrow. The obvious alternative, deregistering the tombstone * and its descendants outright, reaches past the entry that is stale: the * tombstone's descendant set can be a strict superset of the restored copy's * -- a peer may have added a child into the container after the undoing * replica took its copy -- and deregistering evicts those descendants from * `elementPairMapByCreatedAt` with nothing to put them back. A later change * addressed at one of them then throws inside `applyChangePack` on every * replica, and permanently on the server, which replays the same change log * to rebuild the document and its snapshots. * * What it still does reach is the accounting, and it has to. The subtree is * orphaned by the restore, so dropping the entry is dropping the only thing * that would ever have collected it. Its cost is released from wherever it * sits -- `docSize.gc` for anything a removal moved there, `docSize.live` for * a member a peer added into the container after it was already removed. */ unregisterRemovedElementPair(createdAt: TimeTicket): boolean; /** * `release` forgets the cost of an element that has become unreachable * without being collected, and any collection entry naming it. It leaves * `elementPairMapByCreatedAt` alone: the slot may since have been taken over * by a live element restored under this same createdAt, and that element's * registration has to stand. */ private release; /** * `keyOf` returns the `gcPairMap` key identifying the given pair. */ private keyOf; /** * `registerGCPair` registers the given pair to hash table. */ registerGCPair(pair: GCPair): void; /** * `unregisterGCPair` removes the given pair from the hash table. Called * when a tombstoned node is revived (un-tombstoned) by an * identity-preserving undo, so that a later re-registration (redo) is * not swallowed by the toggle in `registerGCPair`. * * NOTE: must be called AFTER the node's removedAt has been cleared, so * `getDataSize()` no longer includes the tombstone ticket. */ unregisterGCPair(pair: GCPair): void; /** * `getElementMapSize` returns the size of element map. */ getElementMapSize(): number; /** * `getGarbageElementSetSize()` returns the size of removed element set. */ getGarbageElementSetSize(): number; /** * `getObject` returns root object. */ getObject(): CRDTObject; /** * `getGarbageLen` returns length of nodes which can be garbage collected. */ getGarbageLen(): number; /** * `getDocSize` returns the size of the document. */ getDocSize(): DocSize; /** * `deepcopy` copies itself deeply. */ deepcopy(): CRDTRoot; /** * `garbageCollect` purges elements that were removed before the given time. * * A pass can hold a purge back (see `GCParent.purgeBarrierAt`), and holding one back can be * the only reason another is held back: purging a node hands its successor * to the node in front of it, and that successor is one this pass already * found stable. So a pass that both purged and deferred may have more to do, * and the loop repeats until a pass purges nothing new or defers nothing. * Everything held back stays on the worklist for the next vector that covers * it. The repeat also makes the result independent of iteration order, which * decides only how many passes it takes, not what ends up collected. */ garbageCollect(minSyncedVersionVector: VersionVector): number; /** * `collect` runs one collection pass, reporting how much it purged and how * much it held back on a barrier. */ private collect; /** * `toJSON` returns the JSON encoding of this root object. */ toJSON(): string; /** * `toSortedJSON` returns the sorted JSON encoding of this root object. */ toSortedJSON(): string; /** * `getStats` returns the current statistics of the root object. * This includes counts of various types of elements and structural information. */ getStats(): RootStats; /** * `acc` accumulates the given DataSize to Live. */ acc(diff: DataSize): void; /** * `accMovedElement` books the size a move added to the moved element. * * An element already tombstoned when it is moved -- a remove and a move of * the same element, concurrent on two replicas, arrive in some order on each * -- is not in live at all: its whole size was moved to gc when it was * removed. Charging the ticket to live there would leave live permanently * ahead of a rebuild, and gc permanently behind by the same amount, which is * the drift in the delivery order where the remove lands first. The gc charge * also has to be topped up so collection, which subtracts the element's * CURRENT size, does not overshoot. */ accMovedElement(element: CRDTElement, diff: DataSize): void; /** * `accGC` accumulates the given DataSize to gc. * * `docSize.gc` has to stay equal to the sum of the CURRENT size of every * registered pair's child, because collection subtracts exactly that when * it purges one. Registration alone cannot maintain that: writing an * attribute onto a node that is already a tombstone changes the size of a * child that was registered earlier, with no pair of its own to carry the * difference. That is what this reports. */ accGC(diff: DataSize): void; /** * `getGCElementPairs` returns an iterator for all GC element pairs. * This is similar to Go's GCElementPairMap() functionality. */ getGCElementPairs(): IterableIterator; } /** * `CRDTText` is a custom CRDT data type to represent the contents of text editors. * */ declare class CRDTText extends CRDTElement { private rgaTreeSplit; constructor(rgaTreeSplit: RGATreeSplit, createdAt: TimeTicket); /** * `create` a instance of Text. */ static create(rgaTreeSplit: RGATreeSplit, createdAt: TimeTicket): CRDTText; /** * `edit` edits the given range with the given value and attributes. */ edit(range: RGATreeSplitPosRange, content: string, editedAt: TimeTicket, attributes?: Record, versionVector?: VersionVector): [ Array>, Array, DataSize, RGATreeSplitPosRange, Array, Array> ]; /** * `restore` re-establishes removed characters under their original * identities (identity-preserving undo of a deletion). */ restore(spans: Array>, executedAt: TimeTicket, fallbackAnchor?: RGATreeSplitPos): [ Array>, Array>, Array>, DataSize, Array ]; /** * `retombstone` re-deletes previously restored characters (redo). */ retombstone(spans: Array>, executedAt: TimeTicket): [Array, Array>, DataSize]; /** * `toTextChanges` wraps raw RGATreeSplit value changes into `TextChange`s, * mirroring the mapping used by `edit`. */ private toTextChanges; /** * `setStyle` applies the style of the given range. * 01. split nodes with from and to * 02. style nodes between from and to * * @param range - range of RGATreeSplitNode * @param attributes - style attributes * @param editedAt - edited time */ setStyle(range: RGATreeSplitPosRange, attributes: Record, editedAt: TimeTicket, versionVector?: VersionVector): [ Array, DocSize, Array>, Map, Array ]; /** * `removeStyle` removes the style attributes of the given range. * Returns previous attribute values (from first styled node) for reverse operation. */ removeStyle(range: RGATreeSplitPosRange, attributesToRemove: Array, editedAt: TimeTicket, versionVector?: VersionVector): [Array, DocSize, Array>, Map]; /** * `indexRangeToPosRange` returns the position range of the given index range. */ indexRangeToPosRange(fromIdx: number, toIdx: number): RGATreeSplitPosRange; /** * `createRange` returns the position range of the given index range for a * local edit or style. Unlike `indexRangeToPosRange`, it rejects an index * that splits a UTF-16 surrogate pair. * * `content` is given for an edit and omitted for a style. It is checked for * lone surrogates: storing one diverges across SDKs on its own, and the half * then pairs with whatever code unit it is stored next to, which would turn * the index at that seam into one `validateUTF16Boundary` refuses for the * lifetime of the text. A peer running an SDK without this check can still * send such content — the guard is a local-edit contract, not a trust * boundary — but nothing a client of this SDK does can create it. */ createRange(fromIdx: number, toIdx: number, content?: string): RGATreeSplitPosRange; /** * `validateUTF16Boundary` throws when the given position splits a surrogate * pair. At either end of the node it reads the neighbouring node: an edit or * a style carrying a mid-pair offset splits the node there, so a pair can * sit in two nodes on this replica while it is one node on every other, and * an index at that seam is still inside it. `indexToPos` resolves a seam to * the node on its left, so the `offset === content.length` side is the one * an index normally reaches. */ private validateUTF16Boundary; /** * `length` returns size of RGATreeList. */ get length(): number; /** * `getTreeByIndex` returns the tree by index for debugging. */ getTreeByIndex(): SplayTree; /** * `getTreeByID` returns the tree by ID for debugging. */ getTreeByID(): LLRBTree>; /** * `refinePos` refines the given RGATreeSplitPos. */ refinePos(pos: RGATreeSplitPos): RGATreeSplitPos; /** * `normalizePos` normalizes the given RGATreeSplitPos. */ normalizePos(pos: RGATreeSplitPos): RGATreeSplitPos; /** * `getDataSize` returns the data usage of this element. */ getDataSize(): DataSize; /** * `toJSON` returns the JSON encoding of this text. */ toJSON(): string; /** * `toSortedJSON` returns the sorted JSON encoding of this text. */ toSortedJSON(): string; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `toString` returns the string representation of this text. */ toString(): string; /** * `values` returns the content-attributes pair array of this text. */ values(): Array>; /** * `getRGATreeSplit` returns rgaTreeSplit. */ getRGATreeSplit(): RGATreeSplit; /** * `toTestString` returns a String containing the meta data of this value * for debugging purpose. */ toTestString(): string; /** * `deepcopy` copies itself deeply. */ deepcopy(): CRDTText; /** * `findIndexesFromRange` returns pair of integer offsets of the given range. */ findIndexesFromRange(range: RGATreeSplitPosRange): [number, number]; /** * `posToIndex` converts the given position to index. */ posToIndex(pos: RGATreeSplitPos, preferToLeft?: boolean): number; /** * `getGCPairs` returns the pairs of GC. */ getGCPairs(): Array; } /** * `CRDTTextValue` is a value of Text * which has a attributes that expresses the text style. * Attributes are represented by RHT. * */ declare class CRDTTextValue { private attributes; private content; constructor(content: string); /** * `create` creates a instance of CRDTTextValue. */ static create(content: string): CRDTTextValue; /** * `length` returns the length of value. */ get length(): number; /** * `substring` returns a sub-string value of the given range. */ substring(indexStart: number, indexEnd: number): CRDTTextValue; /** * `truncate` shortens this value in place, keeping the object identity so * that GC pairs registered against it are not orphaned. See * `RGATreeSplitValue.truncate`. */ truncate(offset: number): void; /** * `setAttr` sets attribute of the given key, updated time and value. */ setAttr(key: string, content: string, updatedAt: TimeTicket): RHTWrite; /** * `getAttr` returns the attributes of this value. */ getAttrs(): RHT; /** * `toString` returns the string representation of this value. */ toString(): string; /** * `getDataSize` returns the data usage of this value. */ getDataSize(): DataSize; /** * `toJSON` returns the JSON encoding of this value. */ toJSON(): string; /** * `getAttributes` returns the attributes of this value. */ getAttributes(): Record; /** * `getContent` returns the internal content. */ getContent(): string; /** * `purge` purges the given child node. */ purge(node: GCChild): void; /** * `getGCPairs` returns the pairs of GC. */ getGCPairs(): Array; } /** * `CRDTTree` is a CRDT implementation of a tree. */ declare class CRDTTree extends CRDTElement implements GCParent { private indexTree; private nodeMapByID; /** * `pendingGCPairs` buffers GC pairs for nodes that were created * already-tombstoned by splitting a removed node. Such pieces inherit * `removedAt` without ever passing through `remove()`, so they would * otherwise never be registered for GC. `edit` and `style` drain this * buffer into their returned GC pairs. */ private pendingGCPairs; constructor(root: CRDTTreeNode, createdAt: TimeTicket); /** * `rebuildMergeState` reconstructs the `mergedInto` cache on source * parents from the persisted `mergedFrom` field on moved children. * For snapshots written before `mergedAt` was added to the proto, * it also falls back to the source's `removedAt` — an approximation * that may be wrong if the source was later overwritten by a * concurrent delete, but this is the best we can do without the * persisted merge ticket. */ private rebuildMergeState; /** * `create` creates a new instance of `CRDTTree`. */ static create(root: CRDTTreeNode, ticket: TimeTicket): CRDTTree; /** * `findFloorNode` finds node of given id. */ findFloorNode(id: CRDTTreeNodeID): CRDTTreeNode | undefined; /** * `findMergeNode` returns the element whose id is exactly `id`, or * undefined. Unlike `findFloorNode` it refuses a floor-only match (a split * product this replica does not hold) and a text node: a merge pointer * names an element, so either would hand merge logic a node the pointer * never named. * * Every merge-lineage read goes through here, not only the decode that * first sees a pointer: `mergedFrom` is retained on an element payload * (Set/Add/ArraySet), persists on the node inside the live document, and * `mergedInto` is derived from it. Otherwise a made-up offset becomes a * forwarding pointer planted on an unrelated node, which a later, innocent * delete follows to tombstone that node's live children. */ private findMergeNode; /** * `declaredBoundaries` returns the elements the edit's own positions named * as boundaries: the element each position declared as its parent, and * every ancestor of that element. A range stops at those rather than * covering them -- the edit asks to merge their remaining content away, not * to delete it -- so a concurrent merge that already moved their children * where this edit would have put them did this edit's work rather than * something it now has to undo. * * The declared parent is resolved with `findMergeNode`, not a floor lookup: * a floor lookup matches on createdAt alone, so a parentID naming a split * product this replica does not hold would land on the offset-0 element and * hand the skip to a node the position never named. * * The walk upward prefers `mergedFrom` over the physical parent: a prior * merge moves a node under the merge target, so the parent no longer names * the element that enclosed it when the position was declared. The set * doubles as the seen set, guarding against a cycle in a client-supplied * `mergedFrom` chain. Mirrors yorkie's `declaredBoundaries` (yorkie#2042). */ private declaredBoundaries; /** * `resolveMergeTarget` follows the `mergedInto` forwarding chain from the * given node while the current node is a merge-away tombstone, returning * the final live target. When a merge lands on a parent that a prior * concurrent merge already merged away (a chained merge P->Q->R, applied * Q->R before this P->Q), the children must flow to that parent's final * destination so the merge chain stays flat (P->R, not P->Q) and both * replicas converge. The seen set guards against cycles from a concurrent * mutual merge. * * Each link is resolved through `findMergeNode`, so a text node or a * floor-only match cuts the chain: `mergedInto` is derived from the * `mergedFrom` an element payload keeps, so a crafted one can name either, * and the merge hands what this returns straight to `moveChild`. */ private resolveMergeTarget; /** * `mergeSourceOf` returns the id of the removed element whose children a * split has just taken back, or undefined when the split re-creates * nothing. * * A merge moves a boundary element's children into the merge target and * tombstones the element, stamping each moved child with `mergedFrom` * naming it. Reversing that merge is a split, which mints a BRAND-NEW * element -- it cannot revive the tombstone, whose id belongs to a change * every replica already applied -- and moves the stamped children into it. * So a split product holding children stamped for a removed element is the * replacement for that element, and anything recorded against the element * has to follow (#1425). * * Derived from the tree rather than carried on the operation because a peer * has to reach the same conclusion from the change alone: the operation * encodes only the split's tickets, never what they replace. * * Narrow on purpose. A split that merely happens to cut through a merge * target keeps some of the source's children on the left, and its product * is a new sibling rather than the source's stand-in -- re-pointing at it * would move references onto a node holding only part of what they named. * Only a split that takes the source's children back WHOLE reverses the * merge, so `splitTarget` is checked for leftovers. */ private mergeSourceOf; /** * `mergedAnchorInterloperGuard` prepares the §9.4 per-node filter for a * style range whose end position was declared inside a parent that a * merge unknown to the styling client removed. The moved anchor child * resolves in the merge target, so the traversal covers nodes sitting * between the merge-source tombstone and the moved children — nodes the * styling client saw outside its range, after the then-live parent. The * predicate skips exactly those interlopers. */ private mergedAnchorInterloperGuard; /** * `reversedFromAnchorRecovery` prepares the §9.4 from-side counterpart of * `mergedAnchorInterloperGuard` for a style range whose start position was * declared inside a parent that a merge unknown to the styling client * removed. The resolved range then collapses (start past end) and the * traversal misses nodes the styling client covered. The recovery * re-anchors the traversal start just after the last live sibling before * the merge-source tombstone; the caller must style only nodes the * returned predicate positively identifies as interlopers. Stamped nodes * in the span stay out of reach and fail open unstyled — see the §9.4 * known limitations in yorkie's concurrent-merge-split design doc. */ private reversedFromAnchorRecovery; /** * `styleSkipPredicate` builds the per-token skip checks shared by style * and removeStyle, as two predicates over the same state. * * `skipReached` answers "did the change reach this node at all": the * End-token unknown-split-sibling exclusion (§9.1), the §9.6 range-start * guard and the §9.4 merged-anchor interloper filter for the range-end * position. It is about the change, so it holds for every node a style * writes to, however that node was found. * * `skipToken` adds the one restriction that belongs to the index traversal * alone -- the §9.4 from-side recovery re-anchors the traversal start over * nodes the change never covered, so a recovered traversal may touch only * the interlopers the recovery positively identified. Nodes derived from * the change's own positions are not in that widened span and answer to * `skipReached` only. * * `beganInside` is the set of elements THIS replica's resolved range begins * inside -- the resolved from-parent and its ancestors, the only elements a * token traversal reaches through their End token alone. */ private styleSkipPredicate; /** * `beginsAtOrBefore` reports whether the change's declared range-start sits * at or before `node`'s Start token in document order, both measured with * removed nodes included so a concurrent removal between the two moves * neither. A position that does not resolve answers no, as Go's * `beginsAtOrInside` does. */ private beginsAtOrBefore; /** * `declaredParentOf` returns the element a position named as its parent, * or undefined when this replica cannot resolve the position. */ private declaredParentOf; /** * `splitOriginsOf` walks back along `insPrevID` from `node`, feeding each * element it passes to `visit` and stopping when `visit` returns false. * Only `splitElement` sets `insPrevID` on an element, so the chain is * exactly the split lineage; the walker stops a crafted chain that loops * back on itself, and a text link cuts it. */ private splitOriginsOf; /** * `declaredLineageOf` resolves, once for a change, everything * `DeclaredLineage` answers about the element a position declared as its * parent: the element's current ancestry, and the split lineage of each * ancestor. */ private declaredLineageOf; /** * `declaredAncestryHas` walks the CURRENT ancestry of the element a * position named as its parent, up to the root, and reports whether any of * them matches. */ private declaredAncestryHas; /** * `declaredLineage` is `declaredLineageOf` for the element `pos` named as * its parent, or undefined when this replica cannot resolve the position. * * `covers` on the result is "the change's range ended inside this node": * whether the node is the element the position named, or an ancestor of it. * The ancestry is the current one, and a concurrent split moves the children * after the split point into the new right half, so each ancestor is matched * through its split lineage: every product of splitting the node stands for * the node. * * `coversEitherWay` is the same question for the range-start position * (§9.6), matching in BOTH directions along the split lineage: a split of * the element the range began inside leaves the start anchor in whichever * half holds it, and both halves are the element the change began inside. * For the range-end side the extra matches would make a guard that excludes * nodes fail open, so that side uses `covers`. */ private declaredLineage; /** * `unknownSplitSiblings` returns the elements a split concurrent with the * change produced from `node`: its `insNextID` chain, stopped at the first * sibling the change already knew about. A style that covered `node` * covered these too, because the change resolved its range while `node` * was still one piece. */ private unknownSplitSiblings; /** * `splitFamilyOf` walks back along `insPrevID` from an element whose * creation the change did not know, collecting the products a concurrent * split made of a node it did know. It returns the family in document * order, that known node first, or an empty array when the chain reaches * no such node -- a node simply new to the change. */ private splitFamilyOf; /** * `boundaryRangeCovers` reports whether the change declared a range that * covers at least one element, so that reconstructing its boundary * elements is repair rather than invention. A range whose two positions * are equal covers nothing on any replica. A range that resolves * backwards covers nothing here either; only a removal collapses a range, * so an inversion with a live declared ancestry on both ends is the * caller's own and gets nothing. */ private boundaryRangeCovers; /** * `declaredAncestryRemoved` reports whether the element a position named * as its parent, or any ancestor of it, has been removed -- the only way a * range declared forwards can resolve backwards here. */ private declaredAncestryRemoved; /** * `boundaryElements` returns the elements the change reached through a * single token on the replica that issued it: the ancestors of the * range-start position, whose End tokens the range ran past, and the * ancestors of the range-end position, whose Start tokens it ran past -- * each chain stopping below the common ancestor of the two. Each element is * returned with the token the range ran past, so the caller can put it * through the same per-token skip checks the traversal applies. * * These come from the positions the change carries, which never move, so * every replica computes the same set whatever a concurrent merge did to * the index space. */ private boundaryElements; /** * `styleTargets` resolves the nodes a style or removeStyle applies to, * without repeats, along with the size the boundary text splits added to * live. Traversed nodes come in document order; boundary elements * recovered from the change's positions follow them, as in Go. * * The two operations are one range resolution asked to write two * different things, so the resolution lives here once. A node is reported * at most once even though a fully covered element is visited on both its * Start and End tokens; the second write was already a no-op, since RHT * rejects a ticket that is not after the one it holds. * * NOTE(cross-implementation): the set this returns is a replicated * contract -- every SDK and the server have to reach the same nodes for * the same change. It mirrors yorkie's `styleTargets`; the rules are the * "Port specification" in yorkie's docs/design/concurrent-merge-split.md. */ private styleTargets; /** * `orderSameBoundarySplit` decides which node a split at `offset` of * `parent` actually splits, so that concurrent splits of one node at one * boundary land in the same order on every replica. * * `splitElement` places its product directly after the node it splits. * When a concurrent split of the same boundary has already been applied, * that puts the products in arrival order, which differs per replica. The * XML still matches (all but the last product are empty) but position-based * operations that follow do not. * * Order them by ticket instead, newest first, as RGA orders concurrent * inserts after the same node: skip the unknown split siblings with a newer * ticket and split the last of them at its start. The right half lives in * that sibling on this replica, so it moves into our product exactly as it * would have moved out of `parent` on a replica that applied us first. */ private orderSameBoundarySplit; /** * `sharesSplitFamilyParent` reports whether `next` sits under `node`'s * parent, or under a split product of that parent. A multi-level split * moves a sibling under the next level's product, so the two parents * legitimately differ — but only within one split family. Anything beyond * that is not a split sibling of `node`, whatever its insNextID claims. */ private sharesSplitFamilyParent; /** * `advancePastUnknownSplitSiblings` follows the insNextID chain of the * given node, advancing past element-type split siblings that the editing * client did not know about (not in versionVector). */ private advancePastUnknownSplitSiblings; /** * `emptyRunReachesActor` reports whether the insNextID chain starting at * `node` runs through empty, unknown element split siblings only and then * reaches a node created by `actorID`. */ private emptyRunReachesActor; /** * `hasUnknownSplitSibling` checks whether the given element node has a * split sibling (via insNextID) whose creation the editor did not know * about. Used to prevent styling via End tokens when a concurrent split * extended the range into the split sibling. */ private hasUnknownSplitSibling; /** * `registerNode` registers the given node to the tree, keeping a live node * over a tombstone when both claim the same ID. * * Documents written by older clients can carry two nodes under one ID (an * undo that re-inserted a deleted piece by copy). A plain `put` lets the * winner depend on the order the nodes were registered — operation order on * a live document, document order on one rebuilt from a snapshot — so after * a reload the same position resolves to a different node and its offset can * fall outside that node. Keeping the live one makes both orders agree for a * live/tombstone pair, which is the shape those documents carry. * * Two nodes in the same state keep the last-registered-wins behavior, and * stay order-dependent: element IDs issued for a split can legitimately * collide with an inserted node's ID (see the delimiter note in * `TreeEditOperation`), and that resolution order is what the rest of the * tree already assumes. * * A node this refuses stays in the index tree while another node answers for * its ID, so it is reachable by traversal but not by lookup. That is the * intended trade for a duplicate: the alternative is unregistering a node * that positions still resolve through. */ registerNode(node: CRDTTreeNode): void; /** * `dropDuplicateContents` returns the contents that would not put a second * node under an ID already in the tree. * * Content created by an edit carries that edit's lamport and actor, so a * content node whose ID names another change is a copy of a node that * already exists — what the copy-reinsert undo path sends when it reverses a * deletion. Inserting it would leave two nodes under one identity, so the * copy is dropped and the rest of the edit applies. * * Content from this edit's own change is kept even when its ID collides: the * delimiters an element split consumes are simulated rather than replayed, * so an ID issued here can legitimately collide, and dropping it would lose * a node the client already inserted. * * Dropping rather than failing is deliberate: such changes are already in * the history of existing documents, and a change that cannot be replayed is * a document that can never be loaded again. A collision anywhere in a * content node's subtree drops that whole subtree, on the grounds that a * copy is copied whole. */ dropDuplicateContents(contents: Array, editedAt: TimeTicket): Array; /** * `registerPendingGCPair` buffers a GC pair for a node that was born * tombstoned (split off an already-removed node). The pair is picked up * by the next `edit` or `style` call via `drainPendingGCPairs`. `size` * is the net-new size created by the split; it is accounted to * docSize.gc at registration since the node was never live. */ registerPendingGCPair(node: CRDTTreeNode, size: DataSize): void; /** * `pushPendingGCPair` buffers an already-built pair, for garbage whose * parent is not this tree -- an attribute tombstone belongs to the node * holding it, not to the tree. */ pushPendingGCPair(pair: GCPair): void; /** * `drainPendingGCPairs` returns the buffered GC pairs and clears the * buffer. */ drainPendingGCPairs(): Array; /** * `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. * * If `editedAt` is given, then it is used to find the appropriate left node * for concurrent insertion. * * `boundary` selects how a position inside a merged-away parent resolves: * `insert` places it at the insertion boundary in the merge target (before * the first moved child, so RGA ordering breaks ties), while `range` places * it right after the merge-source tombstone so a style range neither grows * over nor shrinks past nodes concurrently inserted at that anchor. */ findNodesAndSplitText(pos: CRDTTreePos, editedAt?: TimeTicket, boundary?: 'insert' | 'range'): [TreeNodePair, DataSize]; /** * `style` applies the given attributes of the given range. */ style(range: [CRDTTreePos, CRDTTreePos], attributes: { [key: string]: string; } | undefined, editedAt: TimeTicket, versionVector?: VersionVector): [ Array, Array, DocSize, Map, Array ]; /** * `removeStyle` removes the given attributes of the given range. */ removeStyle(range: [CRDTTreePos, CRDTTreePos], attributesToRemove: Array, editedAt: TimeTicket, versionVector?: VersionVector): [Array, Array, DocSize, Map]; /** * `styleChangeRange` returns the index and path range a style change on * the given node reports to editors, or undefined when the node is not in * the document. * * The targets come from walks over ids -- split families, merge lineage -- * so one can be a node that is live by `isRemoved` but detached from the * tree, with no parent. `prevSibling` dereferences `parent!` and would * throw on it; a node with no parent has no place in the rendered * document to report either, so the caller reports nothing. */ private styleChangeRange; /** * `edit` edits the tree with the given range and content. * If the content is undefined, the range will be removed. */ edit(range: [CRDTTreePos, CRDTTreePos], contents: Array | undefined, splitLevel: number, editedAt: TimeTicket, issueTimeTicket: (() => TimeTicket) | undefined, versionVector?: VersionVector): [ Array, Array, DataSize, Array, number, number, Set, Array, Array, number, number, Array, Array<[CRDTTreeNodeID, CRDTTreeNodeID]> ]; /** * `editT` edits the given range with the given value. * This method uses indexes instead of a pair of TreePos for testing. */ editT(range: [number, number], contents: Array | undefined, splitLevel: number, editedAt: TimeTicket, issueTimeTicket: () => TimeTicket): [ Array, Array, DataSize, Array, number, number, Set, Array, Array, number, number, Array, Array<[CRDTTreeNodeID, CRDTTreeNodeID]> ]; /** * `move` move the given source range to the given target range. */ move(target: [number, number], source: [number, number], ticket: TimeTicket): void; /** * `pathToTreePos` converts the given path of the node to the TreePos. */ pathToTreePos(path: Array): ReturnType; /** * `purgeBarrierAt` implements `GCParent.purgeBarrierAt`. `findNodesAndSplitText` walks the * parent's children, removed ones included, advancing while the next sibling * was created after the incoming edit; a tombstoned sibling with an older * ticket ends that walk. Purging detaches it from the parent, so the next * sibling inherits the decision and must be causally stable first. */ purgeBarrierAt(node: GCChild): TimeTicket | undefined; /** * `purge` physically purges the given node. */ purge(node: CRDTTreeNode): void; /** * `dissolveMerge` erases the merge lineage a node about to be revived * leaves behind: the forwarding pointer on the source and the * `mergedFrom`/`mergedAt` stamps on the children that merge moved into the * destination. * * `mergedInto` is derivable only for a source that is already a tombstone — * `rebuildMergeState` and the merge in `edit` both require it — so a revived * source that kept either half of the lineage makes the replica running the * undo disagree with one loading a snapshot: keeping `mergedInto` gives the * undoing replica a pointer the snapshot no longer rebuilds, and keeping the * children's `mergedFrom` lets the snapshot rebuild one the moment a redo * (`retombstone`) tombstones the source again. Clearing both leaves nothing * either path can derive, in either direction. * * The destination is resolved through `findMergeNode` for the same reason * the §6.2 cascade does: `mergedInto` is derived from a `mergedFrom` an * element payload may carry, so only an exact element match names a node the * pointer really meant. The source's own pointer is dropped regardless of * whether that lookup succeeds — it is the half that is never persisted. */ private dissolveMerge; /** * `restore` re-establishes the nodes described by `spans` under their * ORIGINAL identities (identity-preserving Tree undo): live → skip * (idempotent), tombstoned → unremove in place, purged → recreate. Spans * must be in parent-before-child order (`edit()` captures them that way). * * Returns `[untombstoned, recreated, pairs, diff]`: * - `untombstoned`: nodes revived in place (caller unregisters their GC pairs); * - `recreated`: brand-new nodes rebuilt for purged ranges (caller adds their * size to Live); * - `pairs`: pending GC pairs for born-removed remainders split off a removed * straddler (caller registers them BEFORE unregistering the untombstoned); * - `diff`: the metadata overhead of splitting live straddlers (caller `acc`s * it to Live); * - `edits`: one insertion per node that became visible, in the order it * did. Each is measured right after its node comes back, so applying them * one after another reproduces the result. */ restore(spans: Array, editedAt: TimeTicket): [ Array, Array, Array, DataSize, Array ]; /** * `isolateTextRange` splits `piece` so that a node exactly covering the * absolute-offset interval [from, to) of its insertion exists, and returns * it. Splitting at the caller's boundaries — rather than skipping a piece * that straddles them — is what lets concurrent restores converge on the * same text-node segmentation across replicas (the tree analogue of * RGATreeSplit.isolateRange). A live split's metadata overhead is added to * `diff`; a removed split buffers a pending GC pair internally (contributing * zero here). Requires pieceStart <= from < to <= pieceEnd. */ private isolateTextRange; /** * `retombstone` re-deletes the nodes described by `spans` (redo of an * identity-preserving undo). Live pieces only; idempotent. A piece that * straddles a span boundary is split at that boundary so only the in-span * range is re-removed (symmetric with restore's isolate, so undo/redo stay * mirror images and segmentation stays convergent). Returns the GC pairs for * the newly tombstoned nodes, the live-split metadata overhead, and one * deletion per visible node it removed, each measured right before the * removal so they apply one after another. */ retombstone(spans: Array, executedAt: TimeTicket): [Array, DataSize, Array]; /** * `visibleRangeOf` returns the index range `node` covers and its paths, or * undefined when it or one of its ancestors is removed and so takes no room * in the index. */ private visibleRangeOf; /** * `makeInsertionChange` describes `node` becoming visible as an insertion * at its current position. A node still hidden under a removed ancestor * produces nothing. */ private makeInsertionChange; /** * `findPiecesOverlapping` collects surviving pieces (live or tombstoned) of * the text insertion `createdAt` overlapping [start, end), in ascending * offset order, via descending floorEntry probes. */ private findPiecesOverlapping; /** * `recreateFromSpan` rebuilds a purged node (or purged text sub-range) * under its original identity and attaches it. Anchor ladder, each rung * doing floor-lookup + parent-identity check: * (a) same-insertion successor/predecessor piece (text) → exact slot; * (b) captured left boundary sibling still under this parent → after it; * (c) captured right boundary sibling still under this parent → before it; * (d) deterministic id-order fallback: insert among the parent's current * children at the first position whose id compares greater than the * node's id (pure function of ids → identical on every replica). * Parent genuinely absent → skip (B1): the node stays unplaced/invisible; * convergent, because every replica resolves parent-absent identically. * Parent present but TOMBSTONED → the node is placed but born tombstoned, * stamped with the parent's `removedAt`, and returned as undefined (see * `attach` below). */ private recreateFromSpan; /** * `leftAnchorID` returns the id to store as a restore span's left-sibling * anchor. For a text node the anchor is its LAST character's offset, not its * start: a concurrent delete may later split the left neighbor, and only the * last-char offset floor-resolves to the rightmost fragment (the true left * neighbor of the restored node). For elements (never split by offset) the * node's own id is exact. Right-sibling anchors always use the start offset, * which floor-resolves to the leftmost fragment — the true right neighbor. */ private leftAnchorID; /** * `compareNodeID` totally orders two ids: createdAt (lamport, then actorID) * then offset. Used by the deterministic id-order restore fallback so a * recreated node lands in the same slot on every replica. */ private compareNodeID; /** * `getGCPairs` returns the pairs of GC. */ getGCPairs(): Array; /** * `findPos` finds the position of the given index in the tree. It rejects * an index inside a UTF-16 surrogate pair. */ findPos(index: number, preferText?: boolean): CRDTTreePos; /** * `validateUTF16Boundary` throws when the given text position splits a * surrogate pair. At either end of the node it reads the neighbouring text * node: converting a position back to an index splits text nodes with no * operation, so a pair can sit in two nodes on this replica while it is * one node on every other, and an index at that seam is still inside it. */ private validateUTF16Boundary; /** * `findPosUnchecked` is `findPos` without the surrogate pair check. It is * for indexes the document computed itself, such as an undo range * reconciled against a remote edit, which can land inside a pair through no * fault of the caller. Refusing such an index would only drop the undo, so * it resolves the way it did before the check existed. */ findPosUnchecked(index: number, preferText?: boolean): CRDTTreePos; /** * `pathToPosRange` converts the given path of the node to the range of the position. * * The end index is derived here rather than supplied by the caller, so it * goes through `findPosUnchecked`: the caller named a node by path, and * refusing the range because the index one past that node happens to land * inside a surrogate pair would reject a request that is valid as given. */ pathToPosRange(path: Array): [CRDTTreePos, CRDTTreePos]; /** * `pathToPos` finds the position of the given index in the tree by path. */ pathToPos(path: Array): CRDTTreePos; /** * `getRoot` returns the root node of the tree. */ getRoot(): CRDTTreeNode; /** * `getSize` returns the size of the tree. */ getSize(): number; /** * `getNodeSize` returns the size of the LLRBTree. */ getNodeSize(): number; /** * `getIndexTree` returns the index tree. */ getIndexTree(): IndexTree; /** * toXML returns the XML encoding of this tree. */ toXML(): string; /** * `getDataSize` returns the data usage of this element. */ getDataSize(): DataSize; /** * `toJSON` returns the JSON encoding of this tree. */ toJSON(): string; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `toJSInfoForTest` returns detailed TreeNode information for use in Devtools. */ toJSInfoForTest(): Devtools.TreeNodeInfo; /** * `getRootTreeNode` returns the converted value of this tree to TreeNode. */ getRootTreeNode(): TreeNode; /** * `toTestTreeNode` returns the JSON of this tree for debugging. */ toTestTreeNode(): TreeNodeForTest; /** * `toSortedJSON` returns the sorted JSON encoding of this tree. */ toSortedJSON(): string; /** * `deepcopy` copies itself deeply. */ deepcopy(): CRDTTree; /** * `toPath` converts the given CRDTTreeNodeID to the path of the tree. */ toPath(parentNode: CRDTTreeNode, leftNode: CRDTTreeNode): Array; /** * `toIndex` converts the given CRDTTreeNodeID to the index of the tree. * If includeRemoved is true, it includes removed nodes in the calculation. */ toIndex(parentNode: CRDTTreeNode, leftNode: CRDTTreeNode, includeRemoved?: boolean): number; /** * `indexToPath` converts the given tree index to path. */ indexToPath(index: number): Array; /** * `pathToIndex` converts the given path to index. */ pathToIndex(path: Array): number; /** * `indexRangeToPosRange` returns the position range from the given index range. * It converts a selection, not an edit range, so it skips the surrogate pair * check. */ indexRangeToPosRange(range: [number, number]): TreePosRange; /** * `indexRangeToPosStructRange` converts the integer index range into the Tree position range structure. * Like `indexRangeToPosRange`, it is for selections and skips the surrogate * pair check. */ indexRangeToPosStructRange(range: [number, number]): TreePosStructRange; /** * `posRangeToPathRange` converts the given position range to the path range. */ posRangeToPathRange(range: TreePosRange): [Array, Array]; /** * `posRangeToIndexRange` converts the given position range to the path range. */ posRangeToIndexRange(range: TreePosRange): [number, number]; /** * `traverseInPosRange` traverses the tree in the given position range. * If includeRemoved is true, it includes removed nodes in the calculation. */ private traverseInPosRange; /** * `toTreePos` converts the given nodes to the position of the IndexTree. * If includeRemoved is true, it includes removed nodes in the calculation. */ private toTreePos; /** * `makeDeletionChanges` converts nodes to be deleted to deletion changes. */ private makeDeletionChanges; /** * `findRightToken` returns the token to the right of the given token in the tree. */ private findRightToken; /** * `findLeftToken` returns the token to the left of the given token in the tree. */ private findLeftToken; } /** * `CRDTTreeNode` is a node of CRDTTree. It includes the logical clock and * links to other nodes to resolve conflicts. */ declare class CRDTTreeNode extends IndexTreeNode implements GCParent, GCChild { id: CRDTTreeNodeID; removedAt?: TimeTicket; attrs?: RHT; /** * `insPrevID` is the previous node id of this node after the node is split. */ insPrevID?: CRDTTreeNodeID; /** * `insNextID` is the previous node id of this node after the node is split. */ insNextID?: CRDTTreeNodeID; /** * `mergedFrom` records the parent this node logically belongs to when * a merge relocated it into the merge target: the source parent it was * moved out of, or the declared parent of an insert redirected by the * §9.4 intended-parent stamp. Persisted in the snapshot encoding as * the witness of the merge relationship. */ mergedFrom?: CRDTTreeNodeID; /** * `mergedAt` records the immutable ticket of the merge operation. * Persisted alongside `mergedFrom` because the source parent's * `removedAt` may be overwritten by later LWW tombstones and thus * cannot serve as the merge-time causal boundary for splitElement's * Fix 8 version-vector check. */ mergedAt?: TimeTicket; /** * `mergedInto` is a runtime cache set on the source parent pointing * at the merge target. Set locally during merge execution and rebuilt * from `mergedFrom` on snapshot load — on both paths only while the * source is a tombstone, so `unremove` drops it again. Used for the fast * "is this tombstoned parent a merge source?" check in * `FindTreeNodesWithSplitText`; the alternative (scanning * `nodeMapByID` on every position resolution) would be too expensive. */ mergedInto?: CRDTTreeNodeID; _value: string; constructor(id: CRDTTreeNodeID, type: string, opts?: string | Array, attributes?: RHT, removedAt?: TimeTicket); /** * `toIDString` returns the IDString of this node. */ toIDString(): string; /** * `getRemovedAt` returns the time when this node was removed. */ getRemovedAt(): TimeTicket | undefined; /** * `create` creates a new instance of CRDTTreeNode. */ static create(id: CRDTTreeNodeID, type: string, opts?: string | Array, attributes?: RHT): CRDTTreeNode; /** * `deepcopy` copies itself deeply. */ deepcopy(): CRDTTreeNode; /** * `value` returns the value of the node. */ get value(): string; /** * `value` sets the value of the node. */ set value(v: string); /** * `dropSplitLinks` clears the split-sibling links on this node and every one * of its descendants. * * insPrevID/insNextID name positions in a split chain and only * `splitElement` may create them. A node arriving as operation content is * freshly created by the editing client, so it can never legitimately be a * split product — but the wire format carries the links regardless, and the * walks that read them treat them as trusted structural pointers. * * The merge lineage is deliberately left alone here: unlike operation * content, an element payload can be a deep copy of real document state * (the reverse of a Remove restores the tree as it stood, merges and all), * and erasing mergedFrom/mergedAt would switch off the §1.1 insert redirect * and the §6.2 propagation skip for a tree that legitimately earned them. * Only `dropEngineOnlyLinks`, which runs on content no merge can have * touched, clears those. */ dropSplitLinks(): void; /** * `dropEngineOnlyLinks` clears the engine-only links on this node and every * one of its descendants: the split-sibling chain and the merge lineage. * * It is the operation-content counterpart of `dropSplitLinks`. * `mergedFrom`/`mergedAt` name the parent a node was moved out of and only * a merge may stamp them (`edit` restamps them on the content it inserts, * from the merge parent it resolves locally), so content arriving on a * TreeEdit -- always freshly created by the editing client, never a copy of * live state -- can never legitimately carry them, while the §1.1 redirect * and §6.2 propagation read them as trusted structural pointers. * `mergedInto` goes with them: the decoder derives it from `mergedFrom`, so * leaving it would keep a source pointing at a destination no field records * any more. */ dropEngineOnlyLinks(): void; /** * `clearTombstones` clears the tombstone on this node and every one of its * descendants, restoring the sizes a decoded tombstone suppressed. * * Like the engine-only links, `removedAt` is carried by the wire format on * every tree node yet operation content can never legitimately hold it: a * TreeEdit's content is freshly created by the editing client, so a node * arriving tombstoned is a crafted one. Left in place, `edit` counts it * into the live data size and registers no GC pair for it under a live * parent, while `isRemoved` hides it from every later edit. * * Cleared via `unremove` so each node's padded size is given back to its * ancestors. `traverseAll` is post-order, so a child is revived before its * parent, and the parent's own size already includes the child when the * parent hands it further up. * * A node's attribute table carries tombstones of its own, and those are * deliberately NOT cleared here. Unlike `removedAt` on the node, a removed * RHT entry on content can be genuine: the undo copy-reinsert path re-sends * a `deepcopy` of nodes a real `removeStyle` tombstoned, and it has to, or * the reinserted node would stop rejecting the stale styles the original * rejects. Stripping them on decode would also make this replica disagree * with every other producer of the same bytes -- an older yorkie-js-sdk, the * Go SDK, and the snapshot the server rebuilds from this very operation -- * which is divergence, not hardening. A crafted one is instead made * harmless the way every other decode path already makes it harmless: * `edit` books it into gc through `CRDTTreeNode.getGCPairs`, the same * routing the snapshot and the Set/Add element payload take through * `CRDTTree.getGCPairs`. */ clearTombstones(): void; /** * `isRemoved` returns whether the node is removed or not. */ get isRemoved(): boolean; /** * `remove` marks the node as removed. */ remove(removedAt: TimeTicket): boolean; /** * `unremove` clears the tombstone of this node (identity-preserving * restore). Mirrors `remove()`'s ancestor-size bookkeeping so the node * becomes visible again in place. * * The forwarding pointer goes with the tombstone: both writers of * `mergedInto` (the merge in `edit` and `rebuildMergeState`) only ever set * it on a source that is already removed, so a live node holding one is a * pointer a snapshot-loading replica would not rebuild. `CRDTTree.restore` * drops the matching `mergedFrom` stamps on the children the merge moved, * so nothing is left for a later re-remove to derive it from either. */ unremove(): void; /** * `cloneText` clones this text node with the given offset. */ cloneText(offset: number): CRDTTreeNode; /** * `cloneElement` clones this element node with the given issueTimeTicket function. */ cloneElement(issueTimeTicket: () => TimeTicket): CRDTTreeNode; /** * `split` splits the given offset of this node. */ split(tree: CRDTTree, offset: number, issueTimeTicket?: () => TimeTicket, versionVector?: VersionVector): [CRDTTreeNode | undefined, DataSize]; /** * `getCreatedAt` returns the creation time of this element. */ getCreatedAt(): TimeTicket; /** * `getOffset` returns the offset of a pos. */ getOffset(): number; /** * `canDelete` checks if node is able to delete. */ canDelete(editedAt: TimeTicket, creationKnown: boolean, tombstoneKnown: boolean): boolean; /** * `canStyle` checks if node is able to style. It answers the same question * as `RGATreeSplitNode.canStyle`, the same way — see the contract there. */ canStyle(versionVector?: VersionVector): boolean; /** * `setAttrs` sets the attributes of the node. */ setAttrs(attrs: { [key: string]: string; }, editedAt: TimeTicket): Array; /** * `purge` purges the given child node. */ purge(node: RHTNode): void; /** * `getDataSize` returns the data size of the node. */ getDataSize(): DataSize; /** * `getGCPairs` returns the pairs of GC. */ getGCPairs(): Array; } /** * `CRDTTreeNodeID` represent an ID of a node in the tree. It is used to * identify a node in the tree. It is composed of the creation time of the node * and the offset from the beginning of the node if the node is split. * * Some of replicas may have nodes that are not split yet. In this case, we can * use `map.floorEntry()` to find the adjacent node. */ declare class CRDTTreeNodeID { /** * `createdAt` is the creation time of the node. */ private createdAt; /** * `offset` is the distance from the beginning of the node if the node is * split. */ private offset; constructor(createdAt: TimeTicket, offset: number); /** * `of` creates a new instance of CRDTTreeNodeID. */ static of(createdAt: TimeTicket, offset: number): CRDTTreeNodeID; /** * `fromStruct` creates a new instance of CRDTTreeNodeID from the given struct. */ static fromStruct(struct: CRDTTreeNodeIDStruct): CRDTTreeNodeID; /** * `createComparator` creates a comparator for CRDTTreeNodeID. */ static createComparator(): Comparator; /** * `getCreatedAt` returns the creation time of the node. */ getCreatedAt(): TimeTicket; /** * `equals` returns whether given ID equals to this ID or not. */ equals(other: CRDTTreeNodeID): boolean; /** * `getOffset` returns returns the offset of the node. */ getOffset(): number; /** * `setOffset` sets the offset of the node. */ setOffset(offset: number): void; /** * `toStruct` returns the structure of this position. */ toStruct(): CRDTTreeNodeIDStruct; /** * `toIDString` returns a string that can be used as an ID for this position. */ toIDString(): string; /** * `toTestString` returns a string containing the meta data of the ticket * for debugging purpose. */ toTestString(): string; } /** * `CRDTTreeNodeIDStruct` represents the structure of CRDTTreeNodeID. * It is used to serialize and deserialize the CRDTTreeNodeID. */ export declare type CRDTTreeNodeIDStruct = { createdAt: TimeTicketStruct; offset: number; }; /** * `CRDTTreeNodeIDStruct` represents the structure of CRDTTreeNodeID. * It is used to serialize and deserialize the CRDTTreeNodeID. */ declare type CRDTTreeNodeIDStruct_2 = { createdAt: TimeTicketStruct_2; offset: number; }; /** * `CRDTTreePos` represent a position in the tree. It is used to identify a * position in the tree. It is composed of the parent ID and the left sibling * ID. If there's no left sibling in parent's children, then left sibling is * parent. */ declare class CRDTTreePos { private parentID; private leftSiblingID; constructor(parentID: CRDTTreeNodeID, leftSiblingID: CRDTTreeNodeID); /** * `of` creates a new instance of CRDTTreePos. */ static of(parentID: CRDTTreeNodeID, leftSiblingID: CRDTTreeNodeID): CRDTTreePos; /** * `fromTreePos` creates a new instance of CRDTTreePos from the given TreePos. */ static fromTreePos(pos: TreePos): CRDTTreePos; /** * `getParentID` returns the parent ID. */ getParentID(): CRDTTreeNodeID; /** * `fromStruct` creates a new instance of CRDTTreeNodeID from the given struct. */ static fromStruct(struct: CRDTTreePosStruct_2): CRDTTreePos; /** * `toStruct` returns the structure of this position. */ toStruct(): CRDTTreePosStruct_2; /** * `toTreeNodePair` 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. */ toTreeNodePair(tree: CRDTTree): TreeNodePair; /** * `getLeftSiblingID` returns the left sibling ID. */ getLeftSiblingID(): CRDTTreeNodeID; /** * `equals` returns whether the given pos equals to this or not. */ equals(other: CRDTTreePos): boolean; /** * `replaceNodeID` returns this position with `prev` replaced by `curr` * wherever it names the parent or the left sibling, or this position * itself when it names neither. */ replaceNodeID(prev: CRDTTreeNodeID, curr: CRDTTreeNodeID): CRDTTreePos; } /** * `CRDTTreePosStruct` represents the structure of CRDTTreePos. */ declare type CRDTTreePosStruct = { parentID: CRDTTreeNodeIDStruct_2; leftSiblingID: CRDTTreeNodeIDStruct_2; }; /** * `CRDTTreePosStruct` represents the structure of CRDTTreePos. */ declare type CRDTTreePosStruct_2 = { parentID: CRDTTreeNodeIDStruct; leftSiblingID: CRDTTreeNodeIDStruct; }; declare type DataSize = { /** * `data` is the size of the data in bytes. */ data: number; /** * `meta` is the size of the metadata in bytes. */ meta: number; }; /** * `DeactivateOptions` are user-settable options used when deactivating clients. */ declare interface DeactivateOptions { /** * `keepalive` is used to enable the keepalive option when deactivating. * If true, the client will request deactivation immediately using `fetch` * with the `keepalive` option enabled. This is useful for ensuring the * deactivation request completes even if the page is being unloaded. */ keepalive?: boolean; /** * `synchronous` is used to enable the synchronous option when deactivating. * If true, the server will wait for all pending operations to complete * before deactivating. */ synchronous?: boolean; } /** * `DecreasedDepthOf` represents the type of the decreased depth of the given depth. */ declare type DecreasedDepthOf = Depth extends 10 ? 9 : Depth extends 9 ? 8 : Depth extends 8 ? 7 : Depth extends 7 ? 6 : Depth extends 6 ? 5 : Depth extends 5 ? 4 : Depth extends 4 ? 3 : Depth extends 3 ? 2 : Depth extends 2 ? 1 : Depth extends 1 ? 0 : -1; /** * `DedupCounter` is a Counter that uses HyperLogLog to count unique actors. * Use `add(actor)` to record a unique visitor. Provides approximate counts * with ~2% error rate. * * ```typescript * doc.update((root) => { * root.uv = new yorkie.DedupCounter(); * root.uv.add(userId); * }); * ``` */ export declare class DedupCounter extends BaseCounter { constructor(); /** * `getValue` returns the value of this counter. Always a number since * DedupCounter only supports IntDedup. */ getValue(): number; /** * `add` records a unique actor in the dedup counter. If the actor has * already been counted, the call is ignored. */ add(actor: string): DedupCounter; } /** * The top-level yorkie namespace with additional properties. * * In production, this will be called exactly once and the result * assigned to the `yorkie` global. * * e.g) `new yorkie.Client(...);` */ declare const _default: { Client: typeof Client; Document: typeof Document_2; MemoryDocStore: typeof MemoryDocStore; Primitive: typeof Primitive; Text: typeof Text_2; Counter: typeof Counter; DedupCounter: typeof DedupCounter; Tree: typeof Tree; Devtools: typeof Devtools; Channel: typeof Channel; ChannelEventType: typeof ChannelEventType; YSON: typeof YSON; LogLevel: typeof LogLevel; setLogLevel: typeof setLogLevel; }; export default _default; /** * `DefaultTextType` is the default type of the text node. * It is used when the type of the text node is not specified. */ declare const DefaultTextType = 'text'; /** * `DefaultTextType` is the default type of the text node. * It is used when the type of the text node is not specified. */ declare const DefaultTextType_2 = "text"; declare namespace Devtools { export { isDocEventForReplay, isDocEventsForReplay, isDocNotificationEvent, Client_2 as Client, JSONElement_2 as JSONElement, ContainerValue, TreeNodeInfo, DocEventForReplay, DocEventsForReplay, DocNotificationEvent, DocNotification } } export { Devtools } /** * `DocEvent` is an event that occurs in `Document`. It can be delivered * using `Document.subscribe()`. */ export declare type DocEvent

= StatusChangedEvent_2 | ConnectionChangedEvent | SyncStatusChangedEvent | SnapshotEvent | LocalChangeEvent | RemoteChangeEvent | PresenceEvent_2

| AuthErrorEvent_2 | EpochMismatchEvent | LocalChangesDroppedEvent_2

| PersistDisabledEvent_2; /** * `DocEvent` is an event that occurs in `Document`. It can be delivered * using `Document.subscribe()`. */ declare type DocEvent_2

= | StatusChangedEvent | ConnectionChangedEvent_2 | SyncStatusChangedEvent_2 | SnapshotEvent_2 | LocalChangeEvent_2 | RemoteChangeEvent_2 | PresenceEvent

| AuthErrorEvent | EpochMismatchEvent_2 | LocalChangesDroppedEvent

| PersistDisabledEvent; declare type DocEventCallbackMap

= { default: NextFn | RemoteChangeEvent | SnapshotEvent>; presence: NextFn>; 'my-presence': NextFn | PresenceChangedEvent

>; others: NextFn | UnwatchedEvent

| PresenceChangedEvent

>; connection: NextFn; status: NextFn; sync: NextFn; 'auth-error': NextFn; 'epoch-mismatch': NextFn; 'local-changes-dropped': NextFn>; 'persist-disabled': NextFn; all: NextFn>; }; /** * `DocEventForReplay` is an event used to replay a document. */ declare type DocEventForReplay

= | StatusChangedEvent | SnapshotEvent_2 | LocalChangeEvent_2 | RemoteChangeEvent_2 | InitializedEvent_2

| WatchedEvent_2

| UnwatchedEvent_2

| PresenceChangedEvent_2

; /** * `DocEventForReplay` is an event used to replay a document. */ declare type DocEventForReplay_2

= StatusChangedEvent_2 | SnapshotEvent | LocalChangeEvent | RemoteChangeEvent | InitializedEvent

| WatchedEvent

| UnwatchedEvent

| PresenceChangedEvent

; /** * `DocEvents` represents document events that occur within * a single transaction (e.g., doc.update). */ export declare type DocEvents

= Array>; /** * `DocEventsForReplay` is a list of events used to replay a document. */ declare type DocEventsForReplay = Array; /** * `DocEventsForReplay` is a list of events used to replay a document. */ declare type DocEventsForReplay_2 = Array; /** * `DocEventType` represents the type of the event that occurs in `Document`. */ export declare enum DocEventType { /** * status changed event type */ StatusChanged = "status-changed", /** * `ConnectionChanged` means that the watch stream connection status has changed. */ ConnectionChanged = "connection-changed", /** * `SyncStatusChanged` means that the document sync status has changed. */ SyncStatusChanged = "sync-status-changed", /** * snapshot event type */ Snapshot = "snapshot", /** * local document change event type */ LocalChange = "local-change", /** * remote document change event type */ RemoteChange = "remote-change", /** * `Initialized` means that online clients have been loaded from the server. */ Initialized = "initialized", /** * `Watched` means that the client has established a connection with the server, * enabling real-time synchronization. */ Watched = "watched", /** * `Unwatched` means that the connection has been disconnected. */ Unwatched = "unwatched", /** * `PresenceChanged` means that the presences of the client has updated. */ PresenceChanged = "presence-changed", /** * `AuthError` indicates an authorization failure in syncLoop or watchLoop. */ AuthError = "auth-error", /** * `EpochMismatch` indicates the document was compacted on the server * and this client must detach and reattach to recover. */ EpochMismatch = "epoch-mismatch", /** * `LocalChangesDropped` indicates the offline-persistence layer had to * discard un-pushed local changes it could not reconcile with the server * (a stale-epoch re-anchor, a server-side GC/purge of the document, or a * store reused under a different actor). The event carries the dropped * changes so the app can surface the data loss and, if it wishes, re-apply * them on top of the re-anchored state. */ LocalChangesDropped = "local-changes-dropped", /** * `PersistDisabled` indicates the offline-persistence layer stopped * persisting this document because writing it costs more than the configured * budget allows. Editing continues; durability does not. An app that reports * sync state should say so, since the user's work is no longer being kept. */ PersistDisabled = "persist-disabled" } /** * `DocEventType` represents the type of the event that occurs in `Document`. */ declare enum DocEventType_2 { /** * status changed event type */ StatusChanged = 'status-changed', /** * `ConnectionChanged` means that the watch stream connection status has changed. */ ConnectionChanged = 'connection-changed', /** * `SyncStatusChanged` means that the document sync status has changed. */ SyncStatusChanged = 'sync-status-changed', /** * snapshot event type */ Snapshot = 'snapshot', /** * local document change event type */ LocalChange = 'local-change', /** * remote document change event type */ RemoteChange = 'remote-change', /** * `Initialized` means that online clients have been loaded from the server. */ Initialized = 'initialized', /** * `Watched` means that the client has established a connection with the server, * enabling real-time synchronization. */ Watched = 'watched', /** * `Unwatched` means that the connection has been disconnected. */ Unwatched = 'unwatched', /** * `PresenceChanged` means that the presences of the client has updated. */ PresenceChanged = 'presence-changed', /** * `AuthError` indicates an authorization failure in syncLoop or watchLoop. */ AuthError = 'auth-error', /** * `EpochMismatch` indicates the document was compacted on the server * and this client must detach and reattach to recover. */ EpochMismatch = 'epoch-mismatch', /** * `LocalChangesDropped` indicates the offline-persistence layer had to * discard un-pushed local changes it could not reconcile with the server * (a stale-epoch re-anchor, a server-side GC/purge of the document, or a * store reused under a different actor). The event carries the dropped * changes so the app can surface the data loss and, if it wishes, re-apply * them on top of the re-anchored state. */ LocalChangesDropped = 'local-changes-dropped', /** * `PersistDisabled` indicates the offline-persistence layer stopped * persisting this document because writing it costs more than the configured * budget allows. Editing continues; durability does not. An app that reports * sync state should say so, since the user's work is no longer being kept. */ PersistDisabled = 'persist-disabled', } /** * @generated from enum yorkie.v1.DocEventType */ declare enum DocEventType_3 { /** * @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 } /** * `DocNotification` is a `DocNotificationEvent` stamped with the time the SDK * observed it. The panel can receive the record long after the fact, in the * initial full sync, so the SDK is the only place that knows when it happened. */ declare type DocNotification = { event: DocNotificationEvent; timestamp: number; }; /** * `DocNotification` is a `DocNotificationEvent` stamped with the time the SDK * observed it. The panel can receive the record long after the fact, in the * initial full sync, so the SDK is the only place that knows when it happened. */ declare type DocNotification_2 = { event: DocNotificationEvent_2; timestamp: number; }; /** * `DocNotificationEvent` is an event that cannot be used to replay a document. * `Document.applyDocEventsForReplay` has no case for it, so devtools shows it * as a standalone record instead of feeding it to the replay pipeline. */ declare type DocNotificationEvent

= | ConnectionChangedEvent_2 | SyncStatusChangedEvent_2 | AuthErrorEvent | EpochMismatchEvent_2 | LocalChangesDroppedEvent

| PersistDisabledEvent; /** * `DocNotificationEvent` is an event that cannot be used to replay a document. * `Document.applyDocEventsForReplay` has no case for it, so devtools shows it * as a standalone record instead of feeding it to the replay pipeline. */ declare type DocNotificationEvent_2

= ConnectionChangedEvent | SyncStatusChangedEvent | AuthErrorEvent_2 | EpochMismatchEvent | LocalChangesDroppedEvent_2

| PersistDisabledEvent_2; /** * `DocSize` represents the size of a document in bytes. */ declare type DocSize = { /** * `live` is the size of the document in bytes. */ live: DataSize; /** * `gc` is the size of the garbage collected data in bytes. */ gc: DataSize; }; /** * `DocStatus` represents the status of the document. */ export declare enum DocStatus { /** * Detached means that the document is not attached to the client. * The actor of the ticket is created without being assigned. */ Detached = "detached", /** * Attached means that this document is attached to the client. * The actor of the ticket is created with being assigned by the client. */ Attached = "attached", /** * Removed means that this document is removed. If the document is removed, * it cannot be edited. */ Removed = "removed" } /** * `DocStatus` represents the status of the document. */ declare enum DocStatus_2 { /** * Detached means that the document is not attached to the client. * The actor of the ticket is created without being assigned. */ Detached = 'detached', /** * Attached means that this document is attached to the client. * The actor of the ticket is created with being assigned by the client. */ Attached = 'attached', /** * Removed means that this document is removed. If the document is removed, * it cannot be edited. */ Removed = 'removed', } /** * `DocStore` is a pluggable persistence backend for offline document state. * * It is deliberately a snapshot plus an append-only change log rather than one * opaque blob. Re-serializing the whole document on every edit costs time * proportional to the document — hundreds of milliseconds on a large one — and * a document is at its largest while it is being edited, which is exactly when * the writes happen. Appending costs the size of one change, which does not * grow with the document at all. * * The interface stays byte-oriented and async so a durable backend (IndexedDB, * say) can implement it without the client knowing which storage it talks to, * and so a backend is free to compress or encrypt what it is handed. The * default `MemoryDocStore` keeps everything in a process-local map and carries * no dependency. */ export declare interface DocStore { /** * `load` returns the persisted state for the given document key, or * `undefined` when nothing has been stored for it. `changes` must be ordered * by ascending `clientSeq`. */ load(docKey: string): Promise; /** * `saveSnapshot` replaces the snapshot and atomically drops every appended * change **and any stored meta**. This is compaction: the new snapshot * already contains those changes, so keeping them would replay them twice, * and it embeds a newer header than meta holds, so keeping that would * regress the client's clocks. */ saveSnapshot(docKey: string, bytes: Uint8Array): Promise; /** * `appendChange` appends one local change. This is the hot path — frequent * and small — so an implementation must not rewrite the whole entry to * satisfy it. * * It is an **upsert keyed by `clientSeq`**: re-appending a change already * stored replaces it rather than duplicating it, so a retried write is safe. */ appendChange(docKey: string, change: StoredChange): Promise; /** * `saveMeta` records the post-sync header. It leaves the snapshot alone — * an online client syncs constantly, and re-snapshotting per sync would * reintroduce the cost this interface exists to avoid — and it leaves the * **log** alone too. * * That second part is load-bearing. The log does two jobs: it holds * un-pushed changes so they survive a reload, and it is the delta between * the snapshot and the document's current content. Deleting acknowledged * entries serves the first job and destroys the second, because nothing * brings the snapshot forward on a push-ack — the content would then exist * in neither place while the persisted `serverSeq` claims the server has it. * Only compaction trims the log, and it does so by folding the entries into * a new snapshot first. * * The header itself carries the acknowledged `clientSeq`, so a restore reads * it from there; the store needs no separate parameter for it. * * It is a no-op when nothing is stored for the key. */ saveMeta(docKey: string, bytes: Uint8Array): Promise; /** * `remove` deletes everything persisted for the document key. It is a no-op * when nothing is stored. */ remove(docKey: string): Promise; } /** * `DocSyncStatus` represents the result of synchronizing the document with the server. */ export declare enum DocSyncStatus { /** * `Synced` means that document synced successfully. */ Synced = "synced", /** * `SyncFiled` means that document synchronization has failed. */ SyncFailed = "sync-failed" } /** * `DocSyncStatus` represents the result of synchronizing the document with the server. */ declare enum DocSyncStatus_2 { /** * `Synced` means that document synced successfully. */ Synced = 'synced', /** * `SyncFiled` means that document synchronization has failed. */ SyncFailed = 'sync-failed', } /** * `Document` is a CRDT-based data type. We can represent the model * of the application and edit it even while offline. * It implements Attachable interface to be managed by Attachment. */ declare class Document_2 implements Attachable { private key; private status; private opts; private maxSizeLimit; private schemaRules; private changeID; private checkpoint; private localChanges; private epoch; private docID; private root; private presences; private clone?; private internalHistory; private isUpdating; private onlineClients; private eventStream; private eventStreamObserver; private localChangeStream; private localChangeObserver; private disableGC; private disablePresence; private presenceDropWarned; /** * `history` is exposed to the user to manage undo/redo operations. */ history: { canUndo: () => boolean; canRedo: () => boolean; undo: () => void; redo: () => void; }; constructor(key: string, opts?: DocumentOptions); /** * `update` executes the given updater to update this document. */ update(updater: (root: JSONObject, presence: Presence

) => void, message?: string): void; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the document is changed. */ subscribe(next: DocEventCallbackMap

['default'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the clients watching the document * establishe or update its presence. */ subscribe(type: 'presence', next: DocEventCallbackMap

['presence'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the current client establishes or updates its presence. */ subscribe(type: 'my-presence', next: DocEventCallbackMap

['my-presence'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the client establishes or terminates a connection, * or updates its presence. */ subscribe(type: 'others', next: DocEventCallbackMap

['others'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the stream connection status changes. */ subscribe(type: 'connection', next: DocEventCallbackMap

['connection'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the document status changes. */ subscribe(type: 'status', next: DocEventCallbackMap

['status'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the document is synced with the server. */ subscribe(type: 'sync', next: DocEventCallbackMap

['sync'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the targetPath or any of its nested values change. */ subscribe, TOpInfo extends OpInfoOf>(targetPath: TPath, next: NextFn | RemoteChangeEvent>, error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the authentification error occurs. */ subscribe(type: 'auth-error', next: DocEventCallbackMap

['auth-error'], error?: ErrorFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when an epoch mismatch error occurs. */ subscribe(type: 'epoch-mismatch', next: DocEventCallbackMap

['epoch-mismatch'], error?: ErrorFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the offline-persistence layer had to * discard un-pushed local changes it could not reconcile (a data-loss event). */ subscribe(type: 'local-changes-dropped', next: DocEventCallbackMap

['local-changes-dropped'], error?: ErrorFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. * The callback will be called when the offline-persistence layer stopped * persisting this document because writing it exceeds the configured budget. * Editing continues; durability does not. */ subscribe(type: 'persist-disabled', next: DocEventCallbackMap

['persist-disabled'], error?: ErrorFn): Unsubscribe; /** * `subscribe` registers a callback to subscribe to events on the document. */ subscribe(type: 'all', next: DocEventCallbackMap

['all'], error?: ErrorFn, complete?: CompleteFn): Unsubscribe; /** * `publish` triggers an event in this document, which can be received by * callback functions from document.subscribe(). */ publish(events: DocEvents

): void; /** * `applyChangePack` applies the given change pack into this document. * 1. Remove local changes applied to server. * 2. Update the checkpoint. * 3. Do Garbage collection. */ applyChangePack(pack: ChangePack

): void; /** * `getCheckpoint` returns the checkpoint of this document. */ getCheckpoint(): Checkpoint; /** * `getEpoch` returns the document's last-known compaction epoch. */ getEpoch(): bigint; /** * `getDocID` returns the server-assigned document id recorded on attach, or * an empty string before the first attach (or for a legacy envelope that * predates docID persistence). */ getDocID(): string; /** * `setDocID` records the server-assigned document id so the next persisted * envelope carries it for the Tier-3 silent-purge guard. */ setDocID(docID: string): void; /** * `getChangeID` returns the change id of this document. */ getChangeID(): ChangeID; /** * `hasLocalChanges` returns whether this document has local changes or not. */ hasLocalChanges(): boolean; /** * `toBytes` serializes the full restorable state of this document into a * self-contained byte envelope: the root and presences (as a snapshot), the * checkpoint, the changeID (lamport, version vector, actor), and the pending * local changes. `fromBytes` reverses it, so a document survives a reload * with its un-pushed edits intact. The envelope is a length-prefixed * concatenation of existing byte encodings rather than a new protobuf message. */ toBytes(): Uint8Array; /** * `fromBytes` reconstructs a document from the bytes produced by `toBytes`, * restoring the root, presences, checkpoint, changeID, and pending local * changes. */ static fromBytes(key: string, bytes: Uint8Array, opts?: DocumentOptions): Document_2; /** * `restoreFromBytes` rehydrates this document in place from the bytes * produced by `toBytes`, overwriting the root, presences, checkpoint, * changeID, and pending local changes. Unlike the static `fromBytes`, it * mutates the existing instance so a document the caller already holds (and * is about to attach) recovers its persisted, un-pushed state. * * Ordering: the caller must have stamped the actor (`setActor`) before * calling this. The rehydrated changes and changeID carry the actor they * were persisted under, and the snapshot's element actors are restored as * persisted, so this does not rely on `setActor` rewriting existing element * actors (a documented limitation of `setActor`). * * Actor guard: the persisted changeID must carry the same actor the caller * just stamped. If a store is reused under a different clientKey the current * stable actor differs from the persisted one; restoring anyway would stamp * subsequent edits with the current actor while the restored root/changes * keep the persisted actor, silently diverging the CRDT against a server that * keys on the current actor. On mismatch this throws `ErrClientNotActivated`- * free `ErrInvalidArgument` so the store-backed attach path can surface a * data-loss event and re-anchor instead of corrupting state. */ restoreFromBytes(bytes: Uint8Array): void; /** * `advanceClientSeqTo` moves this document's `clientSeq` counter forward to * the given sequence, and never backward. * * It exists for the one caller that has to undo a persisted header without * undoing the counter inside it. `restoreFromBytes` returns checkpoint, * epoch and `changeID` to what the snapshot carries, which is right for a * header the appended log cannot back — except for the counter. A counter is * not a claim about content the way a checkpoint is: it records which * `clientSeq` values this client has already MINTED, and the server has * taken some of them. Rewinding it to the snapshot's counter mints those * sequences a second time; the server skips them as duplicates and the next * ack, whose `clientSeq` covers them, drops them from `localChanges` as * pushed. The edits are lost with no event. * * The position to hand over is the acked checkpoint, not the header's * counter. The server validates continuity from the position it holds, so * the next change must be its `clientSeq` plus one; the counter can lead * that, and resuming there would mint past the server and wedge every later * push on `ErrInvalidClientSeq`. * * The counter only ever rises, so the guard is the whole contract: a caller * that hands over a stale position cannot pull the document back into * reusing sequence numbers. */ advanceClientSeqTo(clientSeq: number): void; /** * `getPendingChangeStructs` returns the serialized structs of the current * un-pushed local changes. Used by the offline-persistence layer to carry the * dropped changes in a `LocalChangesDropped` data-loss event so the app can * surface (and optionally re-apply) edits that could not be reconciled. */ getPendingChangeStructs(): Array>; /* Excluded from this release type: subscribeLocalChangesInternal */ /** * `getPendingChangesAfter` returns the un-pushed local changes whose * `clientSeq` is above the given one, each paired with that sequence. * * The pairing is the point: a `ChangeStruct` carries its `clientSeq` encoded * inside the hex `changeID`, so a caller working from structs alone cannot * tell which changes it has already seen without decoding them. The * offline-persistence layer needs exactly that to append only what is new. */ getPendingChangesAfter(clientSeq: number): Array<{ clientSeq: number; struct: ChangeStruct_2

; }>; /** * `metaToBytes` serializes just the checkpoint and changeID — the client's * position against the server — without touching the root. * * This is what the offline-persistence layer writes after a sync. A sync * advances the checkpoint while leaving the document unchanged, so * re-serializing the whole document to record it would cost time * proportional to the document for information that is a few dozen bytes. * Without it a restore would resume from whatever checkpoint the last * snapshot happened to carry. */ metaToBytes(): Uint8Array; /** * `restoreMetaFromBytes` applies the bytes produced by `metaToBytes`, * overwriting the checkpoint and changeID. Trailing blobs stay optional, the * same extension rule the `toBytes` envelope follows. */ restoreMetaFromBytes(bytes: Uint8Array): void; /** * `restoreAppendedChanges` replays changes that were recorded *after* the * snapshot this document was restored from, as the offline-persistence * layer's change log holds them. * * These are the opposite case to the pending changes carried inside a * `toBytes` envelope. Those are already reflected in the snapshot's root — * `toBytes` serializes the live root — so `fromBytes` queues them without * applying. A change from the log was written after that root was captured, * so it must be both **applied**, to bring the root forward, and **queued**, * so it is still pushed. Doing only the first loses the edit on reconnect; * doing only the second leaves the user looking at stale content. * * The log must be contiguous and ascending by `clientSeq`. A caller that * cannot satisfy that should restore from the snapshot alone and report the * loss rather than replaying a broken run. */ restoreAppendedChanges(structs: Array>, ackedClientSeq?: number): void; /** * `resetForReanchor` drops all local state that was seeded from a stale * persisted envelope so the document can be re-attached fresh. The server * then re-anchors the client from the current snapshot. Used only on the * store-backed attach path when the resume is rejected with * `ErrEpochMismatch`: the persisted checkpoint/epoch/changeID and any * un-pushed local changes are stale relative to the compacted document, so * presenting them again would just be rejected. This mirrors constructing a * brand-new Document instance without forcing the caller to swap the object * reference it already holds. */ resetForReanchor(): void; /** * `ensureClone` make a clone of root. */ ensureClone(): void; /** * `createChangePack` create change pack of the local changes to send to the * remote server. */ createChangePack(): ChangePack

; /** * `setActor` sets actor into this document. This is also applied in the local * changes the document has. */ setActor(actorID: ActorID): void; /** * `setDisableGC` records whether this document participates in GC. The * client calls this on attach so subsequent applyChange runs use the * lamport-only sync path. */ setDisableGC(disableGC: boolean): void; /** * `setDisablePresence` records the server-fixated presence-disabled state * of this document. The client calls this on attach (before * `applyChangePack`) so any subsequent `Document.update` invocation sees * the gating state already settled. Flipping the flag at runtime is * supported: the next `update` honours the new value. */ setDisablePresence(disablePresence: boolean): void; /** * `isPresenceDisabled` returns the current presence-disabled state of * this document. Reflects the server-fixated value once attached; * before attach it reflects the local construction option. */ isPresenceDisabled(): boolean; /** * `isEnableDevtools` returns whether devtools is enabled or not. */ isEnableDevtools(): boolean; /** * `getKey` returns the key of this document. */ getKey(): string; /** * `getStatus` returns the status of this document. */ getStatus(): DocStatus; /** * `getClone` returns this clone. */ getClone(): { root: CRDTRoot; presences: Map; } | undefined; /** * `getCloneRoot` returns clone object. */ getCloneRoot(): CRDTObject | undefined; /** * `getRoot` returns a new proxy of cloned root. */ getRoot(): JSONObject; /** * `getDocSize` returns the size of this document. */ getDocSize(): DocSize; /** * `getMaxSizePerDocument` gets the maximum size of this document. */ getMaxSizePerDocument(): number; /** * `setMaxSizePerDocument` sets the maximum size of this document. */ setMaxSizePerDocument(size: number): void; /** * `getSchemaRules` gets the schema rules of this document. */ getSchemaRules(): Rule[]; /** * `setSchemaRules` sets the schema rules of this document. */ setSchemaRules(rules: Array): void; /** * `garbageCollect` purges elements that were removed before the given time. */ garbageCollect(minSyncedVersionVector: VersionVector): number; /** * `getRootObject` returns root object. */ getRootObject(): CRDTObject; /** * `getGarbageLen` returns the length of elements should be purged. */ getGarbageLen(): number; /** * `getRootCRDT` returns the CRDTRoot for testing purposes. * This method is intended for internal testing only. */ getRootCRDT(): CRDTRoot; /** * `getGarbageLenFromClone` returns the length of elements should be purged from clone. */ getGarbageLenFromClone(): number; /** * `toJSON` returns the JSON encoding of this document. */ toJSON(): string; /** * `toSortedJSON` returns the sorted JSON encoding of this document. */ toSortedJSON(): string; /** * `getStats` returns the statistics of this document. */ getStats(): RootStats; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `applySnapshot` applies the given snapshot into this document. */ applySnapshot(serverSeq: bigint, snapshotVector: VersionVector, snapshot?: Uint8Array, clientSeq?: number): void; /** * `clearHistory` flushes both undo and redo stacks. This is used * after applying a snapshot or initialRoot so that setup operations * are not reachable via undo. */ clearHistory(): void; /** * `applyChanges` applies the given changes into this document. */ applyChanges(changes: Array>, source: OpSource): void; /** * `applyChange` applies the given change into this document. */ applyChange(change: Change

, source: OpSource): void; /** * `applyChangeInternal` applies the given change into the clone and the root. */ private applyChangeInternal; /** * `applyWatchInit` applies the watch initialization with the given client IDs. */ applyWatchInit(clientIDs: Array): void; /** * `applyDocEvent` applies the given doc event into this document. */ applyDocEvent(type: DocEventType_3, publisher: string): void; /** * `applyStatus` applies the document status into this document. */ applyStatus(status: DocStatus): void; /** * `applyDocEventsForReplay` applies the given events into this document. */ applyDocEventsForReplay(events: Array>): void; /** * `getValueByPath` returns the JSONElement corresponding to the given path. */ getValueByPath(path: string): JSONElement | undefined; /** * `setOnlineClients` sets the given online client set. */ setOnlineClients(onlineClients: Set): void; /** * `resetOnlineClients` resets the online client set. */ resetOnlineClients(): void; /** * `addOnlineClient` adds the given clientID into the online client set. */ addOnlineClient(clientID: ActorID): void; /** * `removeOnlineClient` removes the clientID from the online client set. */ removeOnlineClient(clientID: ActorID): void; /** * `reconcilePresence` compares the previous and current state of a client's * presence/online status and returns the appropriate event to emit. * * For remote clients, "online" means the client is in onlineClients. * For self, "online" means the document status is Attached. * * State transition table: * (!hadP || !wasOn) → (hasP && isOn) : watched (remote) or presence-changed (self) * (hadP && wasOn) → (hasP && isOn) : presence-changed * (hadP && wasOn) → (!hasP || !isOn): unwatched (remote only) * otherwise : no event (waiting) */ private reconcilePresence; /** * `hasPresence` returns whether the given clientID has a presence or not. */ hasPresence(clientID: ActorID): boolean; /** * `getMyPresence` returns the presence of the current client. */ getMyPresence(): P; /** * `getOthersPresences` returns the presences of all other clients. */ getOthersPresences(): Array<{ clientID: ActorID; presence: P; }>; /** * `getPresence` returns the presence of the given clientID. */ getPresence(clientID: ActorID): P | undefined; /** * `getPresences` returns the presences of online clients. */ getPresences(): Array<{ clientID: ActorID; presence: P; }>; /** * `getPresenceForTest` returns the presence of the given clientID * regardless of whether the client is online or not. */ getPresenceForTest(clientID: ActorID): P | undefined; /** * `getSelfForTest` returns the client that has attached this document. */ getSelfForTest(): { clientID: string; presence: P; }; /** * `getOthersForTest` returns all the other clients in online, sorted by clientID. */ getOthersForTest(): { clientID: ActorID; presence: P; }[]; /** * `getUndoStackForTest` returns the undo stack for test. */ getUndoStackForTest(): Array>>; /** * `getRedoStackForTest` returns the redo stack for test. */ getRedoStackForTest(): Array>>; /** * `getVersionVector` returns the version vector of document */ getVersionVector(): VersionVector; private isSameElementOrChildOf; /* Excluded from this release type: acknowledgePushedChanges */ /** * `removePushedLocalChanges` removes local changes that have been applied to * the server from the local changes. * * @param clientSeq - client sequence number to remove local changes before it */ private removePushedLocalChanges; /** * `executeUndoRedo` executes undo or redo operation with shared logic. */ private executeUndoRedo; /** * `executeUndoRedoInternal` pops the history entry and applies it to the * clone and the root. */ private executeUndoRedoInternal; } export { Document_2 as Document } /** * `DocumentOptions` are the options to create a new document. */ declare interface DocumentOptions { /** * `disableGC` disables garbage collection if true. */ disableGC?: boolean; /** * `disablePresence` declares that this document does not use presence. * When true, `Document.update`'s `presence.set` calls are silently * dropped and the server strips any presence that nonetheless reaches * it. The option is server-fixated on first attach — once a document * is created presenceless, subsequent attaches observe `true` from the * attach response regardless of the local option value. Use for * counter-only or other presence-free workloads where the per-client * presence map would otherwise leak memory in long-lived documents. */ disablePresence?: boolean; /** * `enableDevtools` enables devtools if true. */ enableDevtools?: boolean; /** * `maxUndoDepth` is how many changes `history.undo()` can go back, and * likewise for `history.redo()`. Each `Document.update` that changes the * document is one entry; the oldest is dropped when the stack is full. * Defaults to `MaxUndoRedoStackDepth` (50). Must be a positive integer. * A reverse entry keeps a copy of the content it would restore, so a * larger depth holds more memory. */ maxUndoDepth?: number; } /** * `EditOpInfo` represents the information of the edit operation. */ export declare type EditOpInfo = { type: 'edit'; path: string; from: number; to: number; value: { attributes: Indexable; content: string; }; }; /** * `EditOpInfo` represents the information of the edit operation. */ declare type EditOpInfo_2 = { type: 'edit'; path: string; from: number; to: number; value: { attributes: Indexable_2; content: string; }; }; /** * `ElementNode` represents an element node. It has an attributes and children. */ export declare type ElementNode = { type: TreeNodeType_2; attributes?: A; children: Array; }; /** * `ElementNode` represents an element node. It has an attributes and children. */ declare type ElementNode_2 = { type: TreeNodeType; attributes?: A; children: Array; }; /** * ElementRHT is a hashtable with logical clock(Replicated hashtable) * */ declare class ElementRHT { private nodeMapByKey; private nodeMapByCreatedAt; constructor(); /** * `create` creates an instance of ElementRHT. */ static create(): ElementRHT; /** * `set` sets the value of the given key. An existing occupant is removed * only when the incoming value wins the LWW comparison; when it loses, the * occupant stays and the incoming value is marked removed instead. * * Both the win/lose decision and the eviction of the previous occupant are * anchored on the occupant's `positionedAt` (its `movedAt`, falling back to * its `createdAt`). Anchoring them on different tickets lets them disagree: * `CRDTElement.remove` gates on the raw `createdAt`, so for an occupant * whose `createdAt < executedAt < positionedAt` — which is what an undo/redo * restore produces, since it re-places the original element under a fresh * ticket — the eviction fires and tombstones the occupant, while the winner * check decides the incoming value must NOT replace it. The occupant is then * tombstoned but still linked as the key's value, the incoming value is * dropped without being registered as removed, and `get` reports the key as * absent although no operation ever removed it. * * The inner `node.remove(executedAt)` gate is therefore redundant once the * eviction sits inside the winner branch — that branch already guarantees * `executedAt > positionedAt >= createdAt`, which is what * `CRDTElement.remove` checks. It is kept so this reads as the mirror of Go * that it is. * * The losing branch marks the incoming value removed only when it is not * removed already. The marking exists solely to keep a duplicate out of * `ownKeys`, and a value that arrives removed is already out; but * `CRDTElement.remove` accepts any ticket later than the one it holds, so * without the guard it is not a no-op. `converter.fromObject` replays a * decoded object through here, and a decoded tombstone that sorts after the * live occupant would have its `removedAt` bumped from the ticket of the * removal that actually happened to the occupant's `positionedAt` — making * GC on this replica wait on the wrong ticket, and its re-serialized * snapshots and `docSize.gc` disagree with replicas that never reloaded. * * That made rebuilding an object from a snapshot depend on the order its * members happened to arrive in — see * `test/unit/document/crdt/element_rht_order_test.ts`, and * `ElementRHT.SetWithExecutedAt` in `yorkie/pkg/document/crdt/element_rht.go`, * whose anchoring this now mirrors. */ set(key: string, value: CRDTElement, executedAt: TimeTicket): CRDTElement | undefined; /** * `delete` deletes the Element of the given key. */ delete(createdAt: TimeTicket, executedAt: TimeTicket): CRDTElement; /** * `subPathOf` returns the sub path of the given element. */ subPathOf(createdAt: TimeTicket): string | undefined; /** * `purge` physically purge child element. */ purge(element: CRDTElement): void; /** * `deleteByKey` deletes the Element of the given key and removed time. */ deleteByKey(key: string, removedAt: TimeTicket): CRDTElement | undefined; /** * `has` returns whether the element exists of the given key or not. */ has(key: string): boolean; /** * `getByID` returns the node of the given createdAt. */ getByID(createdAt: TimeTicket): ElementRHTNode | undefined; /** * `get` returns the node of the given key. */ get(key: string): ElementRHTNode | undefined; /** * `deepcopy` creates a deep copy of this ElementRHT. */ deepcopy(): ElementRHT; [Symbol.iterator](): IterableIterator; } /** * `ElementRHTNode` is a node of ElementRHT. */ declare class ElementRHTNode { private strKey; private value; constructor(strKey: string, value: CRDTElement); /** * `of` creates a instance of ElementRHTNode. */ static of(strKey: string, value: CRDTElement): ElementRHTNode; /** * `isRemoved` checks whether this value was removed. */ isRemoved(): boolean; /** * `getStrKey` returns the key of this node. */ getStrKey(): string; /** * `getValue` return the value(element) of this node */ getValue(): CRDTElement; /** * `remove` removes a value base on removing time. */ remove(removedAt: TimeTicket): boolean; } declare interface Entry { key: K; value: V; } export declare interface EpochMismatchEvent extends BaseDocEvent_2 { type: DocEventType.EpochMismatch; value: { method: 'PushPull'; }; } declare interface EpochMismatchEvent_2 extends BaseDocEvent { type: DocEventType_2.EpochMismatch; value: { method: 'PushPull'; }; } export declare type ErrorFn = (error: Error) => void; /** * `EventSourceDevPanel` is the name of the source representing messages * from the Devtools panel. */ export declare const EventSourceDevPanel = "yorkie-devtools-panel"; /** * `EventSourceSDK` is the name of the source representing messages * from the SDK. */ export declare const EventSourceSDK = "yorkie-devtools-sdk"; /** * `ExecutionResult` represents the result of operation execution. */ declare type ExecutionResult = { opInfos: Array; reverseOp?: Operation; }; declare type Executor = (observer: Observer) => void; /** * `fromChangePack` converts the given Protobuf format to model format. */ declare function fromChangePack

(pbPack: ChangePack_2): ChangePack

; /** * `fromChanges` converts the given Protobuf format to model format. */ declare function fromChanges

(pbChanges: Array): Array>; /** * `fromPresence` converts the given Protobuf format to model format. */ declare function fromPresence

(pbPresence: Presence_2): P; /** * `fromSchemaRules` converts the given Protobuf format to model format. */ declare function fromSchemaRules(pbRules: Array): Array; /** * `fromTreeNodes` converts the given Protobuf format to model format. */ declare function fromTreeNodes(pbTreeNodes: Array): CRDTTreeNode | undefined; export declare type FullPanelToSDKMessage = PanelToSDKMessage & { source: 'yorkie-devtools-panel'; }; export declare type FullSDKToPanelMessage = SDKToPanelMessage & { source: 'yorkie-devtools-sdk'; }; /** * `GCChild` is an interface for the child of the garbage collection target. */ declare interface GCChild { toIDString(): string; getRemovedAt(): TimeTicket | undefined; getDataSize(): DataSize; } /** * `GCPair` is a structure that represents a pair of parent and child for garbage * collection. */ declare type GCPair = { parent: GCParent; child: GCChild; /** * `gcOnlySize` is set when the child's size was never counted in * `docSize.live`: a piece born removed by splitting an already-tombstoned * node, a tree node recreated already-tombstoned by a restore because its * parent has been removed since (see `CRDTTree.recreateFromSpan`), an * attribute tombstone duplicated by a value copy (a split, or a node * recreated from a span), or a tombstone registered by the full scan when * an element is registered (live only counts visible nodes there). When present, * `registerGCPair` adds this size to `docSize.gc` and leaves * `docSize.live` untouched, instead of moving the child's size from live * to gc. */ gcOnlySize?: DataSize; }; /** * `GCParent` is an interface for the parent of the garbage collection target. */ declare interface GCParent { purge(node: GCChild): void; /** * `purgeBarrierAt` is an optional capability of a GC parent whose surviving * order is decided by which nodes are still linked. * * Every such container resolves a concurrent insert by walking forward from * the anchor and stopping at the first node whose positioning ticket does * not follow the insert: `RGATreeList.findNextBeforeExecutedAt`, the skip in * `RGATreeSplit.findNodeWithSplit`, and the sibling skip in * `CRDTTree.findNodesAndSplitText`. The walk reads the nodes currently * linked, tombstones included, so a tombstone with a small ticket is a hard * barrier that ends the walk. Purging it physically unlinks it, which means * collection mutates the input to the insertion rule: a replica that has * collected sends a still-in-flight insert past the node behind the * tombstone, a replica that has not does not, and the two orders never * reconverge. * * `removedAt` alone does not authorise the unlink. What does is the node * that would become the walk's new stopping point: once that node is * causally stable, every future insert carries a ticket after it, so every * future walk stops there whether or not the tombstone in front of it still * exists. This returns that successor's positioning ticket, which * `CRDTRoot.garbageCollect` requires the version vector to cover as well as * `removedAt`, or undefined when the child has no successor (or is not a * child of this kind) and unlinking it cannot move anything. * * Mirrors Go's `crdt.GCBarrier` (yorkie `ba82ed91`). */ purgeBarrierAt?(node: GCChild): TimeTicket | undefined; } /** * `hexToBytes` converts the given hex string to byte array. */ declare function hexToBytes(hex: string): Uint8Array; /** * `hexToVersionVector` creates a VersionVector from the given bytes. */ declare function hexToVersionVector(hex: string): VersionVector; /** * `HistoryOperation` is a type of history operation. */ declare type HistoryOperation

= Operation | { type: 'presence'; value: Partial

; }; /** * `IncreaseOpInfo` represents the information of the increase operation. */ export declare type IncreaseOpInfo = { type: 'increase'; path: string; value: number; }; /** * `IncreaseOpInfo` represents the information of the increase operation. */ declare type IncreaseOpInfo_2 = { type: 'increase'; path: string; value: number; }; /** * `Indexable` represents an object with string keys and Json values. It is * used to various places such as the presence or attributes of text elements * and etc. */ export declare type Indexable = Record; /** * `Indexable` represents an object with string keys and Json values. It is * used to various places such as the presence or attributes of text elements * and etc. */ declare type Indexable_2 = Record; /** * `IndexTree` is a tree structure for linear indexing. */ declare class IndexTree> { private root; constructor(root: T); /** * `tokensBetween` returns the tokens between the given range. * If includeRemoved is true, it includes removed nodes in the calculation. */ tokensBetween(from: number, to: number, callback: (token: TreeToken, ended: boolean) => void, includeRemoved?: boolean): void; /** * `traverse` traverses the tree with postorder traversal. */ traverse(callback: (node: T) => void): void; /** * `traverseAll` traverses the whole tree (include tombstones) with postorder traversal. */ traverseAll(callback: (node: T) => void): void; /** * findTreePos finds the position of the given index in the tree. */ findTreePos(index: number, preferText?: boolean): TreePos; /** * `treePosToPath` returns path from given treePos */ treePosToPath(treePos: TreePos): number[]; /** * `pathToIndex` returns index from given path */ pathToIndex(path: Array): number; /** * `pathToTreePos` returns treePos from given path */ pathToTreePos(path: Array): TreePos; /** * `getRoot` returns the root node of the tree. */ getRoot(): T; /** * `getSize` returns the size of the tree. */ get size(): number; /** * `findPostorderRight` finds right node of the given tree position with * postorder traversal. */ findPostorderRight(treePos: TreePos): T | undefined; /** * `indexOf` returns the index of the given tree position. * If includeRemoved is true, it includes removed nodes in the calculation. */ indexOf(pos: TreePos, includeRemoved?: boolean): number; /** * `indexToPath` returns the path of the given index. */ indexToPath(index: number): Array; } /** * `IndexTreeNode` is the node of IndexTree. It is used to represent the * document of text-based editors. */ declare abstract class IndexTreeNode> { type: TreeNodeType_2; parent?: T; _children: Array; visibleSize: number; totalSize: number; constructor(type: TreeNodeType_2, children?: Array); /** * `updateAncestorsSize` updates the size of the ancestors. * It is used when the size of the node is changed. * If includeRemoved is true, it updates ancestors totalSize including removed nodes. */ updateAncestorsSize(delta: number, includeRemoved?: boolean): void; /** * `UpdateDescendantsSize` updates the size of the descendants. It is used when * the tree is newly created and the size of the descendants is not calculated. * If includeRemoved is true, it includes removed nodes in the calculation. */ updateDescendantsSize(includeRemoved?: boolean): number; /** * `isText` returns true if the node is a text node. */ get isText(): boolean; /** * `paddedSize` returns the length of the node including padding. * If includeRemoved is true, it includes removed nodes in the calculation. */ paddedSize(includeRemoved?: boolean): number; /** * `isAncenstorOf` returns true if the node is an ancestor of the given node. */ isAncestorOf(node: T): boolean; /** * `nextSibling` returns the next sibling of the node. */ get nextSibling(): T | undefined; /** * `prevSibling` returns the previous sibling of the node. */ get prevSibling(): T | undefined; /** * `isRemoved` returns true if the node is removed. */ abstract get isRemoved(): boolean; /** * `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 cloneElement(issueTimeTicket: () => TimeTicket): T; /** * `value` returns the value of the node. */ abstract get value(): string; /** * `value` sets the value of the node. */ abstract set value(v: string); /** * `getDataSize` returns the size of the node. */ abstract getDataSize(): DataSize; /** * `splitText` splits the given node at the given offset. */ splitText(offset: number, absOffset: number): [T | undefined, DataSize]; /** * `children` returns the children of the node. */ get children(): Array; /** * `allChildren` returns all the children of the node including tombstone nodes. * It returns the shallow copy of the children. */ get allChildren(): Array; /** * `hasTextChild` returns true if the node's children consist of only text children. */ hasTextChild(): boolean; /** * `getChildrenText` returns text value of all text type children. */ getChildrenText(): string; /** * `append` appends the given nodes to the children. */ append(...newNode: Array): void; /** * `prepend` prepends the given nodes to the children. It is only used * for creating a new node from snapshot. */ prepend(...newNode: Array): void; /** * `insertBefore` inserts the given node before the given child. */ insertBefore(newNode: T, referenceNode: T): void; /** * `insertAfter` inserts the given node after the given child. */ insertAfter(newNode: T, referenceNode: T): void; /** * `insertAt` inserts the given node at the given offset. */ insertAt(newNode: T, offset: number): void; /** * `removeChild` removes the given child. * In this method, the child is physically removed from the tree. */ removeChild(child: T): void; /** * `detachChild` removes the given child from this node's children list * and updates both visibleSize and totalSize. Unlike `removeChild` which * is used for GC purge of tombstoned nodes, `detachChild` is used for * moving alive nodes between parents. */ detachChild(child: T): void; /** * `moveChild` detaches the given child from its current parent (if any) * and appends it to this node, preserving both size dimensions on both * parents. Unlike `detachChild` followed by `append`, it is correct for * tombstoned children: a removed node contributes no visibleSize to * either parent (removal already excluded it from its ancestors), so only * the include-removed totalSize is relocated. It is used by merge to move * tombstones as RGA anchors without corrupting index positions. */ moveChild(child: T): void; /** * `moveChildBefore` detaches the given child from its current parent (if * any) and inserts it before `reference` among this node's children, * preserving both size dimensions on both parents. It is `moveChild` with a * position: see there for why a removed child relocates only its * include-removed size. * * Both failures are decided before anything moves, so a refused move leaves * the tree exactly as it was rather than holding a child that belongs to no * parent. The reference's offset is still read after the detach, since * removing the child can shift it when the two share a parent. */ moveChildBefore(child: T, reference: T): void; /** * `detachForMove` takes the child off its current parent, if it has one, * subtracting its sizes from that parent's ancestors, and reports whether * the child is a tombstone — which the re-attachment needs to know too. * * A tombstone moves only its include-removed size: it contributes no * visibleSize to either parent, because removal already took it out of its * ancestors. Splitting the move into this pair and `attachAfterMove` keeps * that rule in one place; stating it once per call site is how the two * dimensions drift apart. */ private detachForMove; /** * `attachAfterMove` adds the child's sizes to its new parent's ancestors, * the mirror of `detachForMove`. `removed` is what that call reported. */ private attachAfterMove; /** * `splitElement` splits the given element at the given offset. */ splitElement(offset: number, issueTimeTicket: () => TimeTicket, versionVector?: VersionVector): [T | undefined, DataSize]; /** * `insertAfterInternal` inserts the given node after the given child. * This method does not update the size of the ancestors. */ insertAfterInternal(newNode: T, referenceNode: T): void; /** * `insertAtInternal` inserts the given node at the given index. * This method does not update the size of the ancestors. */ insertAtInternal(newNode: T, offset: number): void; /** * findOffset returns the offset of the given node in the children. * If includeRemoved is true, it includes removed nodes in the calculation. */ findOffset(node: T, includeRemoved?: boolean): number; /** * `findBranchOffset` returns offset of the given descendant node in this node. * If the given node is not a descendant of this node, it returns -1. */ findBranchOffset(node: T): number; } export declare interface InitializedEvent

extends BaseDocEvent_2 { type: DocEventType.Initialized; source: OpSource.Local; value: Array<{ clientID: ActorID; presence: P; }>; } declare interface InitializedEvent_2

extends BaseDocEvent { type: DocEventType_2.Initialized; source: OpSource_2.Local; value: Array<{ clientID: ActorID_2; presence: P }>; } /** * `isBinData` checks if a value is a YSONBinData object. */ declare function isBinData(value: any): value is YSONBinData { return ( typeof value === 'object' && value !== null && value.type === 'BinData' && typeof value.value === 'string' ); } /** * `isCounter` checks if a value is a YSONCounter object. */ declare function isCounter(value: any): value is YSONCounter { return ( typeof value === 'object' && value !== null && value.type === 'Counter' && typeof value.value === 'object' ); } /** * `isDate` checks if a value is a YSONDate object. */ declare function isDate(value: any): value is YSONDate { return ( typeof value === 'object' && value !== null && value.type === 'Date' && typeof value.value === 'string' ); } /** * `isDedupCounter` checks if a value is a YSONDedupCounter object. */ declare function isDedupCounter(value: any): value is YSONDedupCounter { return ( typeof value === 'object' && value !== null && value.type === 'DedupCounter' && typeof value.value === 'object' && typeof value.registers === 'string' ); } /** * `isDocEventForReplay` checks if an event can be used to replay a document. */ declare function isDocEventForReplay( event: DocEvent_2, ): event is DocEventForReplay { const types = [ DocEventType.StatusChanged, DocEventType.Snapshot, DocEventType.LocalChange, DocEventType.RemoteChange, DocEventType.Initialized, DocEventType.Watched, DocEventType.Unwatched, DocEventType.PresenceChanged, ]; return types.includes(event.type); } /** * `isDocEventsForReplay` checks if a list of events can be used to replay a document. */ declare function isDocEventsForReplay( events: Array, ): events is DocEventsForReplay { return events.every(isDocEventForReplay); } /** * `isDocNotificationEvent` checks if an event should be reported to devtools * as a notification. The list is explicit rather than the complement of * `isDocEventForReplay`, so that a `DocEventType` added later is classified on * purpose instead of landing in this channel by default. */ declare function isDocNotificationEvent( event: DocEvent_2, ): event is DocNotificationEvent { const types = [ DocEventType.ConnectionChanged, DocEventType.SyncStatusChanged, DocEventType.AuthError, DocEventType.EpochMismatch, DocEventType.LocalChangesDropped, DocEventType.PersistDisabled, ]; return types.includes(event.type); } /** * `isInt` checks if a value is a YSONInt object. */ declare function isInt(value: any): value is YSONInt { return ( typeof value === 'object' && value !== null && value.type === 'Int' && typeof value.value === 'number' ); } /** * `isLong` checks if a value is a YSONLong object. */ declare function isLong(value: any): value is YSONLong { return ( typeof value === 'object' && value !== null && value.type === 'Long' && typeof value.value === 'number' ); } /** * `isObject` checks if a value is a plain YSON object (not a special type). */ declare function isObject(value: any): value is { [key: string]: YSONValue } { return ( typeof value === 'object' && value !== null && !Array.isArray(value) && !isText(value) && !isTree(value) && !isInt(value) && !isLong(value) && !isDate(value) && !isBinData(value) && !isCounter(value) && !isDedupCounter(value) ); } /** * `isText` checks if a value is a YSONText object. */ declare function isText(value: any): value is YSONText { return ( typeof value === 'object' && value !== null && value.type === 'Text' && Array.isArray(value.nodes) ); } /** * `isTree` checks if a value is a YSONTree object. */ declare function isTree(value: any): value is YSONTree { return ( typeof value === 'object' && value !== null && value.type === 'Tree' && typeof value.root === 'object' ); } /** * `Json` represents the JSON data type. It is used to represent the data * structure of the document. */ export declare type Json = JsonPrimitive | JsonArray | JsonObject; /** * `Json` represents the JSON data type. It is used to represent the data * structure of the document. */ declare type Json_2 = JsonPrimitive_2 | JsonArray_2 | JsonObject_2; /** * `JSONArray` represents JSON array, but unlike regular JSON, it has time * tickets created by a logical clock to resolve conflicts. */ export declare type JSONArray = { /** * `getID` returns the ID, `TimeTicket` of this Object. */ getID(): TimeTicket; /** * `getElementByID` returns the element for the given ID. */ getElementByID(createdAt: TimeTicket): WrappedElement; /** * `getElementByIndex` returns the element for the given index. */ getElementByIndex(index: number): WrappedElement; /** * `getLast` returns the last element of this array. */ getLast(): WrappedElement; /** * `setValue` sets the given value at the given index. */ setValue(index: number, value: unknown): WrappedElement; /** * `delete` deletes the element of the given index. */ delete(index: number): WrappedElement; /** * `deleteByID` deletes the element of the given ID. */ deleteByID(createdAt: TimeTicket): WrappedElement; /** * `insertBefore` inserts a value before the given next element. */ insertBefore(nextID: TimeTicket, value: any): WrappedElement; /** * `insertAfter` inserts a value after the given previous element. */ insertAfter(prevID: TimeTicket, value: any): WrappedElement; /** * `insertIntegerAfter` inserts a value after the given index. */ insertIntegerAfter(index: number, value: number): WrappedElement; /** * `moveBefore` moves the element before the given next element. */ moveBefore(nextID: TimeTicket, id: TimeTicket): void; /** * `moveAfter` moves the element after the given previous element. */ moveAfter(prevID: TimeTicket, id: TimeTicket): void; /** * `moveAfterByIndex` moves the element after the given index. */ moveAfterByIndex(prevIndex: number, targetIndex: number): void; /** * `moveFront` moves the element before the first element. */ moveFront(id: TimeTicket): void; /** * `moveLast` moves the element after the last element. */ moveLast(id: TimeTicket): void; /** * `elements` returns an iterator of wrapped elements including CRDT metadata. */ elements(): IterableIterator>; /** * `toTestString` returns a String containing the meta data of the node * for debugging purpose. */ toTestString(): string; /** * `toJSForTest` returns the JSON object of this array for debugging. */ toJSForTest(): Devtools.JSONElement; } & Array; declare type JsonArray = Array; declare type JsonArray_2 = Array; /** * `JSONElement` is a wrapper for `CRDTElement` that provides users with an * easy-to-use interface for manipulating `Document`s. */ export declare type JSONElement = PrimitiveValue | JSONObject | JSONArray | Text_2 | Counter | DedupCounter | Tree; /** * `JSONElement` represents the result of `Element.toJSForTest()`. */ declare type JSONElement_2 = { type: JSONElementType; key?: string; value: JSONElementValue; createdAt: string; }; /** * @generated from message yorkie.v1.JSONElementSimple */ declare type JSONElementSimple = Message<"yorkie.v1.JSONElementSimple"> & { /** * @generated from field: yorkie.v1.TimeTicket created_at = 1; */ createdAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket moved_at = 2; */ movedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket removed_at = 3; */ removedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.ValueType type = 4; */ type: ValueType; /** * @generated from field: bytes value = 5; */ value: Uint8Array; }; declare 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()`. */ declare type JSONElementValue = | PrimitiveValue_2 | CounterValue_2 | ContainerValue // Array | Object | Json_2; /** * `JSONObject` represents a JSON object, but unlike regular JSON, it has time * tickets created by a logical clock to resolve conflicts. */ export declare type JSONObject = { /** * `getID` returns the ID(time ticket) of this Object. */ getID(): TimeTicket; /** * `toJSON` returns the JSON encoding of this object. */ toJSON(): string; /** * `toJS` returns the JSON object of this object. */ toJS(): T; /** * `toJSForTest` returns the JSON object of this object for debugging. */ toJSForTest(): Devtools.JSONElement; } & T; declare type JsonObject = { [key: string]: Json | undefined; }; declare type JsonObject_2 = { [key: string]: Json_2 | undefined }; declare type JsonPrimitive = string | number | boolean | null; declare type JsonPrimitive_2 = string | number | boolean | null; /** * `Key` is a string representing the key of Document or Channel. */ declare type Key = string; declare type LeafElement = PrimitiveValue | Primitive | Text_2 | Counter | Tree; /** * `LLRBNode` is node of LLRBTree. */ declare class LLRBNode { key: K; value: V; left?: LLRBNode; right?: LLRBNode; isRed: boolean; constructor(key: K, value: V, isRed: boolean); } /** * LLRBTree is an implementation of Left-learning Red-Black Tree. * * Original paper on Left-leaning Red-Black Trees: * @see http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf * * Invariant 1: No red node has a red child * Invariant 2: Every leaf path has the same number of black nodes * Invariant 3: Only the left child can be red (left leaning) */ declare class LLRBTree { private root?; private comparator; private counter; constructor(comparator?: Comparator); /** * `put` puts the value of the given key. */ put(key: K, value: V): V; /** * `get` gets a value of the given key. */ get(key: K): V | undefined; /** * `remove` removes a element of key. */ remove(key: K): void; /** * `getIterator` returns a new instance of SortedMapIterator. */ getIterator(): SortedMapIterator; /** * `values` returns value array of LLRBTree. */ values(): Array; /** * `floorEntry` returns the entry for the greatest key less than or equal to the * given key. If there is no such key, returns `undefined`. */ floorEntry(key: K): Entry | undefined; /** * `lastEntry` returns last entry of LLRBTree. */ lastEntry(): Entry | undefined; /** * `size` is a size of LLRBTree. */ size(): number; /** * `isEmpty` checks if size is empty. */ isEmpty(): boolean; private getInternal; private putInternal; private removeInternal; private min; private removeMin; private fixUp; private moveRedLeft; private moveRedRight; private isRed; private rotateLeft; private rotateRight; private flipColors; } declare interface LocalBroadcastEvent { type: ChannelEventType.LocalBroadcast; clientID: ActorID; topic: string; payload: Json; options?: BroadcastOptions; } /** * `LocalChangeEvent` is an event that occurs when the document is changed * by local changes. */ export declare interface LocalChangeEvent extends BaseDocEvent_2 { type: DocEventType.LocalChange; source: OpSource.Local | OpSource.UndoRedo; value: ChangeInfo; rawChange?: ChangeStruct_2

; } /** * `LocalChangeEvent` is an event that occurs when the document is changed * by local changes. */ declare interface LocalChangeEvent_2< T = OpInfo_2, P extends Indexable_2 = Indexable_2, > extends BaseDocEvent { type: DocEventType_2.LocalChange; source: OpSource_2.Local | OpSource_2.UndoRedo; value: ChangeInfo_2; rawChange?: ChangeStruct

; } /** * `LocalChangesDroppedEvent` is an app-visible data-loss signal: the persisted * un-pushed local changes could not be reconciled with the server and were * discarded. `value.changes` carries their serialized structs so the app can * surface the loss and optionally re-apply them on top of the recovered state. */ declare interface LocalChangesDroppedEvent< P extends Indexable_2 = Indexable_2, > extends BaseDocEvent { type: DocEventType_2.LocalChangesDropped; value: { reason: LocalChangesDroppedReason; changes: Array>; }; } /** * `LocalChangesDroppedEvent` is an app-visible data-loss signal: the persisted * un-pushed local changes could not be reconciled with the server and were * discarded. `value.changes` carries their serialized structs so the app can * surface the loss and optionally re-apply them on top of the recovered state. */ declare interface LocalChangesDroppedEvent_2

extends BaseDocEvent_2 { type: DocEventType.LocalChangesDropped; value: { reason: LocalChangesDroppedReason_2; changes: Array>; }; } /** * `LocalChangesDroppedReason` enumerates why the offline-persistence layer * had to discard un-pushed local changes it could not reconcile. */ declare type LocalChangesDroppedReason = | 'epoch-reanchor' | 'document-purged' | 'actor-mismatch' | 'restore-failed' // The persisted change log had a `clientSeq` hole — an append that never // landed — so it could not be replayed: the server rejects a discontinuous // run, and a document restored from one would never sync again. | 'log-discontinuity'; /** * `LocalChangesDroppedReason` enumerates why the offline-persistence layer * had to discard un-pushed local changes it could not reconcile. */ declare type LocalChangesDroppedReason_2 = 'epoch-reanchor' | 'document-purged' | 'actor-mismatch' | 'restore-failed' | 'log-discontinuity'; export declare enum LogLevel { Trivial = 0, Debug = 1, Info = 2, Warn = 3, Error = 4, Fatal = 5 } /** * `MemoryDocStore` is an in-memory `DocStore`. It holds entries in a `Map` for * the lifetime of the process and carries no external dependency. It is the * default when a durable backend is not configured, and it doubles as a test * double for the persistence loop. * * Every byte array is copied on the way in and on the way out, so neither a * caller mutating what it wrote nor one mutating what it read can corrupt the * stored entry. */ export declare class MemoryDocStore implements DocStore { private store; constructor(); /** * `load` returns a deep copy of the persisted entry, or `undefined`. */ load(docKey: string): Promise; /** * `saveSnapshot` stores a copy of the bytes and clears the change log. */ saveSnapshot(docKey: string, bytes: Uint8Array): Promise; /** * `appendChange` appends a copy of the change, keeping the log ordered by * `clientSeq`. */ appendChange(docKey: string, change: StoredChange): Promise; /** * `saveMeta` stores a copy of the header, leaving the snapshot and the log * untouched. */ saveMeta(docKey: string, bytes: Uint8Array): Promise; /** * `remove` deletes everything persisted for the document key. */ remove(docKey: string): Promise; } /** * `MoveOpInfo` represents the information of the move operation. */ export declare type MoveOpInfo = { type: 'move'; path: string; previousIndex: number; index: number; }; /** * `MoveOpInfo` represents the information of the move operation. */ declare type MoveOpInfo_2 = { type: 'move'; path: string; previousIndex: number; index: number; }; export declare type NextFn = (value: T) => void; /** * @generated from message yorkie.v1.NodeAttr */ declare type NodeAttr = Message<"yorkie.v1.NodeAttr"> & { /** * @generated from field: string value = 1; */ value: string; /** * @generated from field: yorkie.v1.TimeTicket updated_at = 2; */ updatedAt?: TimeTicket_2; /** * @generated from field: bool is_removed = 3; */ isRemoved: boolean; }; /** * `ObjectOpInfo` represents the OperationInfo for the JSONObject. */ export declare type ObjectOpInfo = SetOpInfo | RemoveOpInfo; /** * `ObjectOpInfo` represents the OperationInfo for the JSONObject. */ declare type ObjectOpInfo_2 = SetOpInfo_2 | RemoveOpInfo_2; /** * `objectToBytes` converts the given JSONObject to byte array. */ declare function objectToBytes(obj: CRDTObject): Uint8Array; export declare interface Observable { subscribe: SubscribeFn; getProxy?: () => ObserverProxy; } /** * Observable interface for subscribing to presence events. */ declare interface Observable_2 { subscribe(observer: (event: T) => void): Unsubscribe; } export declare interface Observer { next: NextFn; error?: ErrorFn; complete?: CompleteFn; } /** * `ObserverProxy` is proxy of `Observer`. */ declare class ObserverProxy implements Observer { finalized: boolean; private observers; private finalError?; constructor(executor: Executor); /** * `next` iterates next observer synchronously. */ next(value: T): void; /** * `error` invoke error. */ error(error: Error): void; /** * `complete` completes observer. */ complete(): void; /** * `subscribe` is a function for subscribing observer. */ subscribe(nextOrObserver: Observer | NextFn, error?: ErrorFn, complete?: CompleteFn): Unsubscribe; private unsubscribeOne; private forEachObserver; private sendOne; private close; } /** * `Operation` represents an operation to be executed on a document. */ declare abstract class Operation { private parentCreatedAt; private executedAt?; constructor(parentCreatedAt: TimeTicket, executedAt?: TimeTicket); /** * `getParentCreatedAt` returns the creation time of the target element to * execute the operation. */ getParentCreatedAt(): TimeTicket; /** * `getExecutedAt` returns execution time of this operation. */ getExecutedAt(): TimeTicket; /** * `setActor` sets the given actor to this operation. */ setActor(actorID: ActorID): void; /** * `setExecutedAt` sets the executedAt. */ setExecutedAt(executedAt: TimeTicket): void; /** * `getEffectedCreatedAt` returns the creation time of the effected element. */ abstract getEffectedCreatedAt(): TimeTicket; /** * `toTestString` returns a string containing the meta data for debugging purpose. */ abstract toTestString(): string; /** * `execute` executes this operation on the given `CRDTRoot`. */ abstract execute(root: CRDTRoot, source: OpSource, versionVector?: VersionVector): ExecutionResult | undefined; } /** * @generated from message yorkie.v1.Operation */ declare type Operation_2 = Message<"yorkie.v1.Operation"> & { /** * @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.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"; } | { /** * @generated from field: yorkie.v1.Operation.ArraySet array_set = 11; */ value: Operation_ArraySet; case: "arraySet"; } | { case: undefined; value?: undefined; }; }; /** * @generated from message yorkie.v1.Operation.Add */ declare type Operation_Add = Message<"yorkie.v1.Operation.Add"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket prev_created_at = 2; */ prevCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.JSONElementSimple value = 3; */ value?: JSONElementSimple; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 4; */ executedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.RestoreMode restore_mode = 5; */ restoreMode: RestoreMode; }; /** * @generated from message yorkie.v1.Operation.ArraySet */ declare type Operation_ArraySet = Message<"yorkie.v1.Operation.ArraySet"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket created_at = 2; */ createdAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.JSONElementSimple value = 3; */ value?: JSONElementSimple; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 4; */ executedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.RestoreMode restore_mode = 5; */ restoreMode: RestoreMode; }; /** * @generated from message yorkie.v1.Operation.Edit */ declare type Operation_Edit = Message<"yorkie.v1.Operation.Edit"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TextNodePos from = 2; */ from?: TextNodePos; /** * @generated from field: yorkie.v1.TextNodePos to = 3; */ to?: TextNodePos; /** * deprecated * * @generated from field: map created_at_map_by_actor = 4; */ createdAtMapByActor: { [key: string]: TimeTicket_2; }; /** * @generated from field: string content = 5; */ content: string; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 6; */ executedAt?: TimeTicket_2; /** * @generated from field: map attributes = 7; */ attributes: { [key: string]: string; }; /** * identity-preserving undo/redo * * @generated from field: repeated yorkie.v1.RestoreSpan restore_spans = 8; */ restoreSpans: RestoreSpan_2[]; /** * @generated from field: yorkie.v1.RestoreMode restore_mode = 9; */ restoreMode: RestoreMode; /** * retombstone_spans is the companion span set for an identity-preserving * reverse op: restore_spans is content the reversed edit removed (to * revive), retombstone_spans is content it inserted (to re-remove). Both * are addressed by original identity so a revived neighbour keeps its * relative order across chained undo/redo. restore_mode selects direction. * * @generated from field: repeated yorkie.v1.RestoreSpan retombstone_spans = 10; */ retombstoneSpans: RestoreSpan_2[]; }; /** * @generated from message yorkie.v1.Operation.Increase */ declare type Operation_Increase = Message<"yorkie.v1.Operation.Increase"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.JSONElementSimple value = 2; */ value?: JSONElementSimple; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 3; */ executedAt?: TimeTicket_2; /** * @generated from field: string actor = 4; */ actor: string; }; /** * @generated from message yorkie.v1.Operation.Move */ declare type Operation_Move = Message<"yorkie.v1.Operation.Move"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket prev_created_at = 2; */ prevCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket created_at = 3; */ createdAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 4; */ executedAt?: TimeTicket_2; }; /** * @generated from message yorkie.v1.Operation.Remove */ declare type Operation_Remove = Message<"yorkie.v1.Operation.Remove"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket created_at = 2; */ createdAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 3; */ executedAt?: TimeTicket_2; }; /** * @generated from message yorkie.v1.Operation.Set */ declare type Operation_Set = Message<"yorkie.v1.Operation.Set"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @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_2; /** * @generated from field: yorkie.v1.RestoreMode restore_mode = 5; */ restoreMode: RestoreMode; }; /** * @generated from message yorkie.v1.Operation.Style */ declare type Operation_Style = Message<"yorkie.v1.Operation.Style"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @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_2; /** * deprecated * * @generated from field: map created_at_map_by_actor = 6; */ createdAtMapByActor: { [key: string]: TimeTicket_2; }; /** * @generated from field: repeated string attributes_to_remove = 7; */ attributesToRemove: string[]; }; /** * @generated from message yorkie.v1.Operation.TreeEdit */ declare type Operation_TreeEdit = Message<"yorkie.v1.Operation.TreeEdit"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TreePos from = 2; */ from?: TreePos_2; /** * @generated from field: yorkie.v1.TreePos to = 3; */ to?: TreePos_2; /** * deprecated * * @generated from field: map created_at_map_by_actor = 4; */ createdAtMapByActor: { [key: string]: TimeTicket_2; }; /** * @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_2; /** * identity-preserving undo/redo * * @generated from field: repeated yorkie.v1.TreeRestoreSpan restore_spans = 8; */ restoreSpans: TreeRestoreSpan_2[]; /** * @generated from field: yorkie.v1.RestoreMode restore_mode = 9; */ restoreMode: RestoreMode; /** * @generated from field: repeated yorkie.v1.TreeRestoreSpan retombstone_spans = 10; */ retombstoneSpans: TreeRestoreSpan_2[]; /** * split_tickets carries the tickets the originating replica issued for the * nodes an element split creates, in issue order. Empty for a change * written before this field existed, which replays through the simulation * that reconstructed them from executed_at and the content count. * * @generated from field: repeated yorkie.v1.TimeTicket split_tickets = 11; */ splitTickets: TimeTicket_2[]; }; /** * @generated from message yorkie.v1.Operation.TreeStyle */ declare type Operation_TreeStyle = Message<"yorkie.v1.Operation.TreeStyle"> & { /** * @generated from field: yorkie.v1.TimeTicket parent_created_at = 1; */ parentCreatedAt?: TimeTicket_2; /** * @generated from field: yorkie.v1.TreePos from = 2; */ from?: TreePos_2; /** * @generated from field: yorkie.v1.TreePos to = 3; */ to?: TreePos_2; /** * @generated from field: map attributes = 4; */ attributes: { [key: string]: string; }; /** * @generated from field: yorkie.v1.TimeTicket executed_at = 5; */ executedAt?: TimeTicket_2; /** * @generated from field: repeated string attributes_to_remove = 6; */ attributesToRemove: string[]; /** * deprecated * * @generated from field: map created_at_map_by_actor = 7; */ createdAtMapByActor: { [key: string]: TimeTicket_2; }; }; /** * `OpInfo` represents the information of an operation. * It is used to inform to the user what kind of operation was executed. */ export declare type OpInfo = TextOpInfo | CounterOpInfo | ArrayOpInfo | ObjectOpInfo | TreeOpInfo; /** * `OpInfo` represents the information of an operation. * It is used to inform to the user what kind of operation was executed. */ declare type OpInfo_2 = | TextOpInfo_2 | CounterOpInfo_2 | ArrayOpInfo_2 | ObjectOpInfo_2 | TreeOpInfo_2; /** * `OpInfoOf` represents the type of the operation info of the given * path in the Document.subscribe. It is used to remove the `$.` prefix. */ declare type OpInfoOf = TKey extends `$.${infer TPath}` ? OpInfoOfInner : OpInfoOfInner; /** * `OpInfoOfElement` represents the type of the operation info of the given element. */ declare type OpInfoOfElement = TElem extends Text_2 ? TextOpInfo : TElem extends Counter ? CounterOpInfo : TElem extends Tree ? TreeOpInfo : TElem extends BaseArray ? ArrayOpInfo : TElem extends BaseObject ? ObjectOpInfo : OpInfo; /** * `OpInfoOfInner` represents the type of the operation info of the * given path in the Document.subscribe. */ declare type OpInfoOfInner = TDepth extends 0 ? OpInfoOfElement : TKeyOrPath extends `${infer TFirst}.${infer TRest}` ? TFirst extends keyof TElem ? OpInfoOfInner> : OpInfo : TKeyOrPath extends keyof TElem ? OpInfoOfElement : OpInfo; /** * `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 declare enum OpSource { Local = "local", Remote = "remote", UndoRedo = "undoredo" } /** * `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. */ declare enum OpSource_2 { Local = 'local', Remote = 'remote', UndoRedo = 'undoredo', } /** * PanelToSDKMessage is a message sent from the Devtools panel to the SDK. */ export declare type PanelToSDKMessage = /** * Informs the SDK that the panel is available. */ { msg: 'devtools::connect'; } /** * Informs the SDK that 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; }; /** * `parse` parses a YSON string into a typed JavaScript object. * * YSON extends JSON to support Yorkie CRDT types: * - `Text([...])` for Text CRDT * - `Tree(...)` for Tree CRDT * - Standard JSON for primitives, objects, and arrays * * @param yson - YSON formatted string * @returns Parsed YSONValue * @throws YorkieError if parsing fails * * @example * ```typescript * const data = parse('{"content":Text([{"val":"Hi"}])}'); * // { content: { type: 'Text', nodes: [{ val: 'Hi' }] } } * * // With type parameter: * const data = parse<{ content: YSONText }>('{"content":Text([{"val":"Hi"}])}'); * // data.content is now typed as YSONText * ``` */ declare function parse(yson: string): T { try { // Preprocess YSON string to handle special types const processed = preprocessYSON(yson); // Parse as JSON const parsed = JSON.parse(processed); // Post-process to restore type information return postprocessValue(parsed) as T; } catch (err) { throw new YorkieError( Code.ErrInvalidArgument, `Failed to parse YSON: ${err instanceof Error ? err.message : String(err)}`, ); } } /** * `PathOf` represents the type of all possible paths in the Document.subscribe. */ declare type PathOf = PathOfInner; /** * `PathOfInner` represents the type of the path of the given element. */ declare type PathOfInner = Depth extends 0 ? Prefix : TElem extends Record ? { [TKey in keyof TElem]: TElem[TKey] extends LeafElement ? `${Prefix}${TKey & string}` : TElem[TKey] extends BaseArray ? `${Prefix}${TKey & string}` | `${Prefix}${TKey & string}.${number}` | PathOfInner> : `${Prefix}${TKey & string}` | PathOfInner>; }[keyof TElem] : Prefix extends `${infer TRest}.` ? TRest : Prefix; /** * `PersistDisabledEvent` reports that this document is no longer being * persisted. It fires once per attachment: the measurement that triggers it is * taken at compaction, and latching tears the persist subscription down, so * the cost of discovering the document is unaffordable is paid once. */ declare interface PersistDisabledEvent extends BaseDocEvent { type: DocEventType_2.PersistDisabled; value: { reason: PersistDisabledReason; bytes: number; millis: number }; } /** * `PersistDisabledEvent` reports that this document is no longer being * persisted. It fires once per attachment: the measurement that triggers it is * taken at compaction, and latching tears the persist subscription down, so * the cost of discovering the document is unaffordable is paid once. */ declare interface PersistDisabledEvent_2 extends BaseDocEvent_2 { type: DocEventType.PersistDisabled; value: { reason: PersistDisabledReason_2; bytes: number; millis: number; }; } declare type PersistDisabledReason = // Serializing the document exceeded `maxPersistBytes`. | 'too-large' // Serializing the document took longer than `maxPersistMillis`. | 'too-slow'; declare type PersistDisabledReason_2 = 'too-large' | 'too-slow'; /** * `Presence` represents a proxy for the Presence to be manipulated from the outside. */ export declare class Presence

{ private context; private presence; constructor(changeContext: ChangeContext, presence: P); /** * `set` updates the presence based on the partial presence. */ set(presence: Partial

, option?: { addToHistory: boolean; }): void; /** * `get` returns the presence value of the given key. */ get(key: K): P[K]; /** * `clear` clears the presence. */ clear(): void; } /** * @generated from message yorkie.v1.Presence */ declare type Presence_2 = Message<"yorkie.v1.Presence"> & { /** * @generated from field: map data = 1; */ data: { [key: string]: string; }; }; /** * `PresenceChange` represents the change of presence. */ declare type PresenceChange

= { type: PresenceChangeType_2.Put; presence: P; } | { type: PresenceChangeType_2.Clear; }; /** * @generated from message yorkie.v1.PresenceChange */ declare type PresenceChange_2 = Message<"yorkie.v1.PresenceChange"> & { /** * @generated from field: yorkie.v1.PresenceChange.ChangeType type = 1; */ type: PresenceChange_ChangeType; /** * @generated from field: yorkie.v1.Presence presence = 2; */ presence?: Presence_2; }; /** * @generated from enum yorkie.v1.PresenceChange.ChangeType */ 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 declare interface PresenceChangedEvent

extends BaseDocEvent_2 { type: DocEventType.PresenceChanged; source: OpSource; value: { clientID: ActorID; presence: P; }; } declare interface PresenceChangedEvent_2< P extends Indexable_2, > extends BaseDocEvent { type: DocEventType_2.PresenceChanged; source: OpSource_2; value: { clientID: ActorID_2; presence: P }; } /** * `PresenceChangeType` represents the type of presence change. */ declare enum PresenceChangeType { Put = 'put', Clear = 'clear', } /** * `PresenceChangeType` represents the type of presence change. */ declare enum PresenceChangeType_2 { Put = "put", Clear = "clear" } /** * `PresenceEvent` is an event that occurs when the presence of a client changes. */ declare type PresenceEvent

= | InitializedEvent_2

| WatchedEvent_2

| UnwatchedEvent_2

| PresenceChangedEvent_2

; /** * `PresenceEvent` is an event that occurs when the presence of a client changes. */ declare type PresenceEvent_2

= InitializedEvent

| WatchedEvent

| UnwatchedEvent

| PresenceChangedEvent

; /** * `PresenceEvent` represents a presence change event. */ declare interface PresenceEvent_3 { /** * `type` is the type of the event. */ type: ChannelEventType.PresenceChanged | ChannelEventType.Initialized; /** * `count` is the current count value. */ count: number; } /** * `Primitive` represents primitive data type including logical clock. * It has a type and a value. */ export declare class Primitive extends CRDTElement { private valueType; private value; constructor(value: PrimitiveValue, createdAt: TimeTicket); /** * `of` creates a new instance of Primitive. */ static of(value: PrimitiveValue, createdAt: TimeTicket): Primitive; /** * `valueFromBytes` parses the given bytes into value. */ static valueFromBytes(primitiveType: PrimitiveType, bytes: Uint8Array): PrimitiveValue; /** * `getValueSize` returns the size of the value. The size is similar to * the size of primitives in JavaScript. */ private getValueSize; /** * `getDataSize` returns the data usage of this element. */ getDataSize(): DataSize; /** * `toJSON` returns the JSON encoding of the value. */ toJSON(): string; /** * `toSortedJSON` returns the sorted JSON encoding of the value. */ toSortedJSON(): string; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `deepcopy` copies itself deeply. */ deepcopy(): Primitive; /** * `getType` returns the type of the value. */ getType(): PrimitiveType; /** * `getPrimitiveType` returns the primitive type of the value. */ static getPrimitiveType(value: unknown): PrimitiveType | undefined; /** * `isSupport` check if the given value is supported type. */ static isSupport(value: unknown): boolean; /** * `isInteger` checks if the given number is integer. */ static isInteger(num: number): boolean; /** * `isNumericType` checks numeric type by JSONPrimitive */ isNumericType(): boolean; /** * `getValue` returns the value of Primitive. */ getValue(): PrimitiveValue; /** * `toBytes` creates an array representing the value. */ toBytes(): Uint8Array; } declare enum PrimitiveType { Null = 0, Boolean = 1, Integer = 2, Long = 3, Double = 4, String = 5, Bytes = 6, Date = 7 } /** * `PrimitiveValue` represents a value of primitive type. Only values of type * included in `PrimitiveValue` can be set to the document. */ export declare type PrimitiveValue = null | boolean | number | bigint | string | Uint8Array | Date; /** * `PrimitiveValue` represents a value of primitive type. Only values of type * included in `PrimitiveValue` can be set to the document. */ declare type PrimitiveValue_2 = // eslint-disable-next-line @typescript-eslint/no-restricted-types null | boolean | number | bigint | string | Uint8Array | Date; /** * `RemoteChangeEvent` is an event that occurs when the document is changed * by remote changes. */ export declare interface RemoteChangeEvent extends BaseDocEvent_2 { type: DocEventType.RemoteChange; source: OpSource.Remote; value: ChangeInfo; rawChange?: ChangeStruct_2

; } /** * `RemoteChangeEvent` is an event that occurs when the document is changed * by remote changes. */ declare interface RemoteChangeEvent_2< T = OpInfo_2, P extends Indexable_2 = Indexable_2, > extends BaseDocEvent { type: DocEventType_2.RemoteChange; source: OpSource_2.Remote; value: ChangeInfo_2; rawChange?: ChangeStruct

; } /** * `RemoveOpInfo` represents the information of the remove operation. */ export declare type RemoveOpInfo = { type: 'remove'; path: string; key?: string; index?: number; }; /** * `RemoveOpInfo` represents the information of the remove operation. */ declare type RemoveOpInfo_2 = { type: 'remove'; path: string; key?: string; index?: number; }; /** * `ResourceStatus` represents the common status interface for attachable resources. */ declare type ResourceStatus = 'detached' | 'attached' | 'removed'; /** * RestoreMode selects the identity-preserving path. RESTORE_MODE_UNSPECIFIED * means an ordinary edit (no restore semantics), keeping forward edits * unchanged on the wire. * * For elements it selects between reviving the element already in the tree and * inserting a copy of it. The copy is what undo does today, and because a * deep copy keeps every descendant's created_at, it puts a second live element * under ids the document is indexed by. Reviving needs a replicated liveness * register -- removed_at paired with revived_at on each element -- so that * every replica resolves a remove/revive race the same way, with a tie going * to the removal as the shipped remove register already does. * * The branch cannot be chosen from local state. A replica that collected * between the removal and the undo has purged the tombstone, and one that * joined from a later snapshot never had it, so "revive if a tombstone is * present" is a function of local collection timing and the same change log * would produce different documents. That is why the branch is on the wire. * * @generated from enum yorkie.v1.RestoreMode */ declare enum RestoreMode { /** * @generated from enum value: RESTORE_MODE_UNSPECIFIED = 0; */ UNSPECIFIED = 0, /** * @generated from enum value: RESTORE_MODE_RESTORE = 1; */ RESTORE = 1, /** * @generated from enum value: RESTORE_MODE_RETOMBSTONE = 2; */ RETOMBSTONE = 2 } /** * `RestoreSpan` identifies a run of characters from a single original * insertion: the absolute-offset interval [start, end) of the insertion * created at `createdAt`. `value` is a deep copy of the removed content, * carried so that purged nodes can be recreated (GC-safe). */ declare type RestoreSpan = { createdAt: TimeTicket; start: number; end: number; value: T; }; /** * RestoreSpan carries a run of characters from a single original text * insertion, addressed by split-invariant absolute offsets [start, end), * for identity-preserving undo/redo. content and attributes are a deep * copy of the removed value so restore is independent of GC state. * * @generated from message yorkie.v1.RestoreSpan */ declare type RestoreSpan_2 = Message<"yorkie.v1.RestoreSpan"> & { /** * @generated from field: yorkie.v1.TimeTicket created_at = 1; */ createdAt?: TimeTicket_2; /** * @generated from field: int32 start = 2; */ start: number; /** * @generated from field: int32 end = 3; */ end: number; /** * @generated from field: string content = 4; */ content: string; /** * @generated from field: map attributes = 5; */ attributes: { [key: string]: string; }; }; /** * `RevisionSummary` represents a document revision for version management. * It stores a snapshot of document content at a specific point in time, * enabling features like rollback, audit, and version history tracking. */ export declare interface RevisionSummary { /** * `id` is the unique identifier of the revision. */ id: string; /** * `label` is a user-friendly name for this revision. */ label: string; /** * `description` is a detailed explanation of this revision. */ description: string; /** * `snapshot` is the serialized document content in YSON format at this revision point. * * Use `YSON.parse()` to convert this string to a typed JavaScript object: * * ```javascript * import { YSON } from 'yorkie-js-sdk'; * const snapshot = YSON.parse(revision.snapshot); * ``` */ snapshot: string; /** * `createdAt` is the time when this revision was created. */ createdAt: Date; } /** * @generated from message yorkie.v1.RevisionSummary */ declare type RevisionSummary_2 = Message<"yorkie.v1.RevisionSummary"> & { /** * @generated from field: string id = 1; */ id: string; /** * @generated from field: string label = 2; */ label: string; /** * @generated from field: string description = 3; */ description: string; /** * @generated from field: string snapshot = 4; */ snapshot: string; /** * @generated from field: google.protobuf.Timestamp created_at = 5; */ createdAt?: Timestamp; }; /** * `RGATreeSplit` is a block-based list with improved index-based lookup in RGA. * The difference from RGATreeList is that it has data on a block basis to * reduce the size of CRDT metadata. When an edit occurs on a block, * the block is split. * */ declare class RGATreeSplit implements GCParent { private head; private treeByIndex; private treeByID; /** * `pendingGCPairs` buffers GC pairs for garbage that no `remove()` call * produced: nodes created already-tombstoned by splitting a removed node, * and attribute tombstones duplicated by a value copy (a split, or * `restore` recreating a purged piece; see `bookCopiedAttrTombstones`). * Either would otherwise never be registered for GC. Callers that split or * restore nodes (`edit`, `CRDTText.setStyle`, `CRDTText.removeStyle`, * `restore`) drain this buffer into their returned GC pairs. */ private pendingGCPairs; constructor(); /** * `create` creates a instance RGATreeSplit. */ static create(): RGATreeSplit; /** * `edit` does following steps * 1. split nodes with from and to * 2. delete between from and to * 3. insert a new node * 4. add removed node * @param range - range of RGATreeSplitNode * @param editedAt - edited time * @param value - value * @returns `[RGATreeSplitPos, Array, DataSize, Array>, Array]` */ edit(range: RGATreeSplitPosRange, editedAt: TimeTicket, value?: T, versionVector?: VersionVector): [ RGATreeSplitPos, Array, DataSize, Array>, Array, Array> ]; /** * `restore` re-establishes the characters described by `spans` under * their ORIGINAL identities. For each span, per overlapping region: * - live piece exists → skip (idempotent; another undo restored it) * - tombstoned piece exists → clear removedAt (un-tombstone) * - no piece exists (GC'd) → recreate a node with the original ID * * Returns [untombstonedNodes, recreatedNodes, changes, liveDiff, * pendingGCPairs]. `changes` describes the revived content as insertions * (ascending index) so editor bindings and remote sync can be driven * the same way as a normal edit. * * The caller must, in order: (1) register every pair in `pendingGCPairs` * — fragments `splitNode` buffered while isolating a target range out of * a larger tombstoned piece, and attribute tombstones copied into split or * recreated values (see `drainPendingGCPairs`); * (2) unregister GC pairs for `untombstonedNodes`. Registering first is * required for `untombstonedNodes` entries whose node was itself one of * those split-born fragments (a target isolated from the interior of a * tombstone) — such a node was never registered under its own id, so * step (1) creates the entry that step (2) then correctly walks from gc * back to live; entries that remain tombstoned (siblings of the * restored target) simply stay registered. Finally, `root.acc(liveDiff)` * accounts the size of any nodes recreated from scratch (the GC'd-away * case), which `splitNode`'s buffering does not cover. */ restore(spans: Array>, executedAt: TimeTicket, fallbackAnchor?: RGATreeSplitPos): [ Array>, Array>, Array>, DataSize, Array ]; /** * `retombstone` re-deletes the characters described by `spans` (redo of * an identity-preserving undo). Only live pieces are affected; already * removed or purged regions are skipped (idempotent). * * Returns [pairs, changes, diff]: GCPairs for the newly tombstoned * nodes, the removed regions as deletions so editor bindings and remote * sync can be driven the same way as a normal edit, and the * metadata-size overhead from splitting the (live) pieces to isolate the * target range. The caller must `root.acc(diff)` before registering * `pairs`, mirroring how a normal edit's boundary splits are accounted * before its resulting tombstones are registered. Indices are captured * before each removal, so applying them in emission order stays * consistent. */ retombstone(spans: Array>, executedAt: TimeTicket): [Array, Array>, DataSize]; /** * `findPiecesOverlapping` collects existing nodes (live or tombstoned) * belonging to the insertion `createdAt` that overlap the absolute-offset * interval [start, end), in ascending offset order. Works by descending * floorEntry probes over treeByID. */ private findPiecesOverlapping; /** * `findPieceCovering` returns the node of insertion `createdAt` whose * absolute-offset range covers `offset`, if present. */ private findPieceCovering; /** * `findRestoreAnchor` returns the physical node to insert a recreated * fragment [gapStart, gapEnd) of insertion `createdAt` AFTER. * * Resolution ladder (all rules key on op-carried data + ID lookups only): * (a) a piece covering gapEnd exists → directly before it * (originally-adjacent successor; exact original slot) * (b) nearest surviving piece of the same insertion left of gapStart * → directly after it * (c) rightmost surviving piece of the same insertion (must be right * of the gap) → directly before it * (d) chain anchor: the previously placed fragment of this same restore * (document order) → after it, so a purged multi-fragment run is * rebuilt left-to-right rather than reversed * (e) the operation's fallback anchor (refined) — same exposure as the * current implementation's fromPos; see design-doc caveat * (f) head (deterministic last resort) */ private findRestoreAnchor; /** * `isolateRange` splits `piece` so that a node exactly covering the * absolute-offset interval [from, to) exists, and returns it along with * the net metadata-size overhead the split(s) introduced. * * When `piece` is live, this overhead is a normal live-bucket cost (same * as any other boundary split) and the caller should `root.acc` it. * When `piece` is tombstoned, `splitNode` itself buffers the overhead of * any born-removed fragment via `pendingGCPairs` (see `drainPendingGCPairs`), * so the returned diff is zero in that case — the caller must still * drain and register those pairs. * * Requires: pieceStart <= from < to <= pieceEnd. */ private isolateRange; /** * `indexToPos` finds RGATreeSplitPos of given offset. */ indexToPos(idx: number): RGATreeSplitPos; /** * `findIndexesFromRange` finds indexes based on range. */ findIndexesFromRange(range: RGATreeSplitPosRange): [number, number]; /** * `posToIndex` converts the given position to index. */ posToIndex(pos: RGATreeSplitPos, preferToLeft: boolean): number; /** * `findNode` finds node of given id. */ findNode(id: RGATreeSplitNodeID): RGATreeSplitNode; /** * `length` returns size of RGATreeSplit. */ get length(): number; /** * `getTreeByIndex` returns the tree by index for debugging purpose. */ getTreeByIndex(): SplayTree; /** * `getTreeByID` returns the tree by ID for debugging purpose. */ getTreeByID(): LLRBTree>; /** * `toString` returns the string encoding of this RGATreeSplit. */ toString(): string; [Symbol.iterator](): IterableIterator>; /** * `getHead` returns head of RGATreeSplitNode. */ getHead(): RGATreeSplitNode; /** * `deepcopy` copies itself deeply. */ deepcopy(): RGATreeSplit; /** * `normalizePos` converts a local position `(id, rel)` into a single * absolute offset measured from the head `(0:0)` of the physical chain. * * The offset is the live length of every node before the floor node of * `id`, plus `rel`. It used to be summed over the `prev` chain; it is now * read from `treeByIndex`, which holds the same sum: every node on the * chain is in it, in chain order, weighted by its live length (a tombstone * stays in with weight zero; only `purge` takes a node out, and `purge` * unlinks it from the chain and from `treeByID` too). Every Edit execution * calls this, so a linear walk here makes typing a document quadratic. * * This is a one-to-one port of the Go implementation (yorkie#2107), and the * result is the chain walk's result for every input, including a floor * lookup that lands on an earlier piece: `rel` is added in the id space of * the floor node, not resolved through `getAbsoluteID`. Resolution stays * the same on purpose - `Document.applyChangeInternal` reconciles the undo * stacks against these offsets, so they must agree with what every other * replica, Go included, computes. */ normalizePos(pos: RGATreeSplitPos): RGATreeSplitPos; /** * `refinePos` remaps the given pos to the current split chain. * * - Traverses the physical `next` chain (not `insNext`). * - Counts only live characters: removed nodes are treated as length 0. * - If the given offset exceeds the length of the current node, * it moves forward through `next` nodes, subtracting lengths, * until the offset fits in a live node. * - If it runs out of nodes, it snaps to the end of the last node. * * Example: * Before split: ["12345"](1:2:0), pos = (1:2:0, rel=5) * After split : ["1"](1:2:0) - ["23"](1:2:1) - ["45"](1:2:3) * refinePos(pos) -> (1:2:3, rel=2) * * Example: * ["12"](1:2:0, live) and pos = (1:2:0, rel=4) * refinePos(pos) -> points two chars after "12", * i.e. advances into following nodes, skipping removed ones. */ refinePos(pos: RGATreeSplitPos): RGATreeSplitPos; /** * `toTestString` returns a String containing the meta data of the node * for debugging purpose. */ toTestString(): string; /** * `insertAfter` inserts the given node after the given previous node. */ insertAfter(prevNode: RGATreeSplitNode, newNode: RGATreeSplitNode): RGATreeSplitNode; /** * `findNodeWithSplit` splits and return nodes of the given position. */ findNodeWithSplit(pos: RGATreeSplitPos, editedAt: TimeTicket): [RGATreeSplitNode, DataSize, RGATreeSplitNode]; private findFloorNodePreferToLeft; private findFloorNode; /** * `findBetween` returns nodes between fromNode and toNode. */ findBetween(fromNode: RGATreeSplitNode, toNode: RGATreeSplitNode): Array>; private splitNode; /** * `bookCopiedAttrTombstones` registers the attribute tombstones a freshly * copied value has just duplicated. `CRDTTextValue.substring` -- which both * `splitNode` and `restore`'s recreate path go through -- deep-copies the * whole RHT, tombstones included; it has to, or a piece would resolve a * concurrent style differently from a replica that never split or never lost * it. Each copy is a fresh piece of garbage under a new parent with no * registration of its own: the original's pair names the original's parent, * so without this the copy sits in the RHT forever, uncounted and * unpurgeable. The copy was never in `docSize.live` -- `getDataSize` excludes * removed attributes -- so `gcOnlySize` charges it to gc alone, and `purge` * subtracts the same size back out. */ private bookCopiedAttrTombstones; /** * `drainPendingGCPairs` returns the GC pairs buffered in `pendingGCPairs` * and clears the buffer. */ drainPendingGCPairs(): Array; private deleteNodes; /** * `findEdgesOfCandidates` finds the edges outside `candidates`, * (which has not already been deleted, or be undefined but not yet implemented) * right edge is undefined means `candidates` contains the end of text. */ private findEdgesOfCandidates; private makeChanges; /** * `deleteIndexNodes` clears the index nodes of the given deletion boundaries. * The boundaries mean the nodes that will not be deleted in the range. */ private deleteIndexNodes; /** * `purgeBarrierAt` implements `GCParent.purgeBarrierAt`. `findNodeWithSplit` skips forward * while the next node was created after the incoming edit, so a tombstone * whose createdAt precedes the edit stops that walk. Unlinking it hands the * next node the stopping decision, which is only the same decision once * that node is causally stable. */ purgeBarrierAt(child: GCChild): TimeTicket | undefined; /** * `purge` physically purges the given node from RGATreeSplit. */ purge(node: RGATreeSplitNode): void; } /** * `RGATreeSplitNode` is a node of RGATreeSplit. */ declare class RGATreeSplitNode extends SplayNode implements GCChild { private id; private removedAt?; private prev?; private next?; private insPrev?; private insNext?; constructor(id: RGATreeSplitNodeID, value?: T, removedAt?: TimeTicket); /** * `create` creates a instance of RGATreeSplitNode. */ static create(id: RGATreeSplitNodeID, value?: T): RGATreeSplitNode; /** * `createComparator` creates a function to compare two RGATreeSplitNodeID. */ static createComparator(): Comparator; /** * `getID` returns the ID of this RGATreeSplitNode. */ getID(): RGATreeSplitNodeID; /** * `getCreatedAt` returns creation time of the Id of RGATreeSplitNode. */ getCreatedAt(): TimeTicket; /** * `getLength` returns the length of this node. */ getLength(): number; /** * `getContentLength` returns the length of this value. */ getContentLength(): number; /** * `getPrev` returns a previous node of this node. */ getPrev(): RGATreeSplitNode | undefined; /** * `getNext` returns a next node of this node. */ getNext(): RGATreeSplitNode | undefined; /** * `getInsPrev` returns a previous node of this node insertion. */ getInsPrev(): RGATreeSplitNode | undefined; /** * `getInsNext` returns a next node of this node insertion. */ getInsNext(): RGATreeSplitNode | undefined; /** * `getInsPrevID` returns a ID of previous node insertion. */ getInsPrevID(): RGATreeSplitNodeID; /** * `setPrev` sets previous node of this node. */ setPrev(node?: RGATreeSplitNode): void; /** * `setNext` sets next node of this node. */ setNext(node?: RGATreeSplitNode): void; /** * `setInsPrev` sets previous node of this node insertion. */ setInsPrev(node?: RGATreeSplitNode): void; /** * `setInsNext` sets next node of this node insertion. */ setInsNext(node?: RGATreeSplitNode): void; /** * `hasNext` checks if next node exists. */ hasNext(): boolean; /** * `hasInsPrev` checks if previous insertion node exists. */ hasInsPrev(): boolean; /** * `isRemoved` checks if removed time exists. */ isRemoved(): boolean; /** * `getRemovedAt` returns the remove time of this node. */ getRemovedAt(): TimeTicket | undefined; /** * `split` creates a new split node of the given offset. */ split(offset: number): RGATreeSplitNode; /** * `canDelete` checks if node is able to delete. */ canRemove(editedAt: TimeTicket, creationKnown: boolean, tombstoneKnown: boolean): boolean; /** * `canStyle` checks if node is able to set style. * * The only question is whether the styling change knew this node existed. * It deliberately does NOT ask whether the node has since been removed, and * that is a convergence requirement rather than a preference: a style is * applied unconditionally on the replica that issues it — the node is live * there, or the range would not have reached it — and can never be * retracted afterwards. Every other replica has to apply it too. * * Any rule that reads `removedAt` is delivery-order dependent, because * `removedAt` is last-writer-wins and MUTABLE: `canRemove` lets a removal * the node has not seen overwrite it, while a style is evaluated once, when * it arrives. Two clients deleting the same run concurrently plus a third * styling over it is enough to make replicas disagree, and no single stored * ticket fixes it — the replica cannot know which of the concurrent * removals the styler had seen. The predicate has to not depend on removal * state at all. * * The cost is that a style covers text the same client had already deleted, * invisibly, so undoing the style and then the deletion brings the text back * without the attributes it carried. That is the price of the replicas * agreeing. */ canStyle(versionVector?: VersionVector): boolean; /** * `setRemovedAt` sets the remove time of this node. */ setRemovedAt(removedAt?: TimeTicket): void; /** * `remove` removes the node of the given edited time. */ remove(removedAt: TimeTicket): void; /** * `createRange` creates ranges of RGATreeSplitPos. */ createPosRange(): RGATreeSplitPosRange; /** * `getData` returns the data of this node. */ getDataSize(): DataSize; /** * `deepcopy` returns a new instance of this RGATreeSplitNode without structural info. */ deepcopy(): RGATreeSplitNode; /** * `toTestString` returns a String containing * the meta data of the node for debugging purpose. */ toTestString(): string; private splitValue; /** * `toIDString` returns a string that can be used as an ID for this position. */ toIDString(): string; } /** * `RGATreeSplitNodeID` is an ID of RGATreeSplitNode. */ declare class RGATreeSplitNodeID { private createdAt; private offset; constructor(createdAt: TimeTicket, offset: number); /** * `of` creates a instance of RGATreeSplitNodeID. */ static of(createdAt: TimeTicket, offset: number): RGATreeSplitNodeID; /** * `fromStruct` creates a instance of RGATreeSplitNodeID from the struct. */ static fromStruct(struct: RGATreeSplitNodeIDStruct): RGATreeSplitNodeID; /** * `getCreatedAt` returns the creation time of this ID. */ getCreatedAt(): TimeTicket; /** * `getOffset` returns returns the offset of this ID. */ getOffset(): number; /** * `equals` returns whether given ID equals to this ID or not. */ equals(other: RGATreeSplitNodeID): boolean; /** * `hasSameCreatedAt` returns whether given ID has same creation time with this ID. */ hasSameCreatedAt(other: RGATreeSplitNodeID): boolean; /** * `split` creates a new ID with an offset from this ID. */ split(offset: number): RGATreeSplitNodeID; /** * `toStruct` returns the structure of this node id. */ toStruct(): RGATreeSplitNodeIDStruct; /** * `toTestString` returns a String containing * the meta data of the node id for debugging purpose. */ toTestString(): string; /** * `toIDString` returns a string that can be used as an ID for this node id. */ toIDString(): string; } /** * `RGATreeSplitNodeIDStruct` is a structure represents the meta data of the node id. * It is used to serialize and deserialize the node id. */ declare type RGATreeSplitNodeIDStruct = { createdAt: TimeTicketStruct; offset: number; }; /** * `RGATreeSplitPos` is the position of the text inside the node. */ declare class RGATreeSplitPos { private id; private relativeOffset; constructor(id: RGATreeSplitNodeID, relativeOffset: number); /** * `of` creates a instance of RGATreeSplitPos. */ static of(id: RGATreeSplitNodeID, relativeOffset: number): RGATreeSplitPos; /** * `fromStruct` creates a instance of RGATreeSplitPos from the struct. */ static fromStruct(struct: RGATreeSplitPosStruct): RGATreeSplitPos; /** * `getID` returns the ID of this RGATreeSplitPos. */ getID(): RGATreeSplitNodeID; /** * `getRelativeOffset` returns the relative offset of this RGATreeSplitPos. */ getRelativeOffset(): number; /** * `getAbsoluteID` returns the absolute id of this RGATreeSplitPos. */ getAbsoluteID(): RGATreeSplitNodeID; /** *`toTestString` returns a String containing * the meta data of the position for debugging purpose. */ toTestString(): string; /** * `toStruct` returns the structure of this node pos. */ toStruct(): RGATreeSplitPosStruct; /** * `equals` returns whether given pos equal to this pos or not. */ equals(other: RGATreeSplitPos): boolean; } declare type RGATreeSplitPosRange = [RGATreeSplitPos, RGATreeSplitPos]; /** * `RGATreeSplitPosStruct` is a structure represents the meta data of the node pos. * It is used to serialize and deserialize the node pos. */ declare type RGATreeSplitPosStruct = { id: RGATreeSplitNodeIDStruct; relativeOffset: number; }; declare interface RGATreeSplitValue { length: number; substring(indexStart: number, indexEnd?: number): RGATreeSplitValue; /** * `truncate` shortens this value in place, keeping the object identity. * * A split has to keep the LEFT node's value object, because `CRDTRoot.keyOf` * identifies a GC pair's parent by object identity. Replacing it orphans * every pair already registered against it: purge is then called on an * object nothing references, so the tombstone survives while the ledger says * it was collected. The Go implementation splits in place for the same * reason. */ truncate(offset: number): void; getDataSize(): DataSize; /** * `getGCPairs` returns the pairs for the tombstones this value carries, for * a value that has any (`CRDTTextValue`'s removed attributes). */ getGCPairs?(): Array; } /** * RHT is replicated hash table by creation time. * For more details about RHT: @see http://csl.skku.edu/papers/jpdc11.pdf */ declare class RHT { private nodeMapByKey; private numberOfRemovedElement; constructor(); /** * `create` creates a new instance of RHT. */ static create(): RHT; /** * `getNodeMapByKey` returns the hashtable of RHT. */ getNodeMapByKey(): Map; /** * `set` sets the value of the given key. */ /** * `RHTWrite` reports what a `set` did, so the caller can keep docSize honest * without inspecting the map afterwards. Reading the map cannot tell a write * that installed a node from one that lost LWW and left the incumbent in * place, and charging live for the latter makes the running size depend on * delivery order. */ set(key: string, value: string, executedAt: TimeTicket): RHTWrite; /** * SetInternal sets the value of the given key internally. * * This is the route a snapshot and a `deepcopy` both take, and it keeps what * it is given verbatim, tombstones included: a peer's bytes are not this * SDK's to rewrite, and a tombstone's value costs nothing either way because * `RHTNode.getDataSize` does not charge it. */ setInternal(key: string, value: string, executedAt: TimeTicket, removed: boolean): void; /** * `remove` removes the Element of the given key. * * The tombstone still STORES the value -- what goes on the wire is unchanged * -- but stops being CHARGED for it, because `RHTNode.getDataSize` skips a * removed node's value. `valueDropped` is what the caller has to take back * out of whichever side of the ledger was holding those bytes; see * `attrGCPair` for which side that is. */ remove(key: string, executedAt: TimeTicket): RHTRemoval; /** * `has` returns whether the element exists of the given key or not. */ has(key: string): boolean; /** * `get` returns the value of the given key. */ get(key: string): string | undefined; /** * `deepcopy` copies itself deeply. */ deepcopy(): RHT; /** * `toJSON` returns the JSON encoding of this hashtable. */ toJSON(): string; /** * `size` returns the size of RHT */ size(): number; /** * `toObject` returns the object of this hashtable. */ toObject(): Record; [Symbol.iterator](): IterableIterator; /** * `purge` purges the given child node. */ purge(child: RHTNode): void; } /** * `RHTNode` is a node of RHT(Replicated Hashtable). */ declare class RHTNode implements GCChild { private key; private value; private updatedAt; private _isRemoved; constructor(key: string, value: string, updatedAt: TimeTicket, isRemoved: boolean); /** * `of` creates a new instance of RHTNode. */ static of(key: string, value: string, createdAt: TimeTicket, isRemoved: boolean): RHTNode; /** * `getKey` returns a key of node. */ getKey(): string; /** * `getValue` returns a value of node. */ getValue(): string; /** * `getUpdatedAt` returns updated time of node. */ getUpdatedAt(): TimeTicket; /** * `isRemoved` returns whether the node has been removed or not. */ isRemoved(): boolean; /** * `toIDString` returns the IDString of this node. */ toIDString(): string; /** * `getRemovedAt` returns the time when this node was removed. */ getRemovedAt(): TimeTicket | undefined; /** * `getDataSize` returns the size of this node. * * A tombstone charges its key only. The value it still carries is dead * weight: nothing reads it -- `has`, `toJSON` and `toObject` all gate on * `isRemoved` -- and charging it made the running `docSize` disagree with a * rebuild of the same document, which replays the same removals. The value * is left on the node rather than cleared so that what this SDK stores and * serializes for a tombstone is byte-for-byte what it was, and what a peer * sends us is kept verbatim: the convergence fix belongs in the accounting, * not in the wire format. */ getDataSize(): DataSize; } /** * `RHTRemoval` is what an `RHT.remove` reports back. */ declare type RHTRemoval = { /** * `gcNodes` are the tombstones this removal made collectable. */ gcNodes: Array; /** * `valueDropped` is the size of the value the removal stopped charging for, * which no node's `getDataSize` accounts for any more. The caller subtracts * it from whichever side of the ledger was holding it: `live` for an * attribute that was live on a live node, `gc` for one on a node that is * itself a tombstone. Zero when the attribute was already a tombstone, since * a tombstone's value was not being charged in the first place. */ valueDropped: DataSize; }; /** * `RHTNode` is a node of RHT(Replicated Hashtable). */ /** * `RHTWrite` is what an `RHT.set` reports back. See `RHT.set`. */ declare type RHTWrite = { /** * `installed` is the node this write put in the map, absent when the write * lost LWW and changed nothing. Its size is what enters docSize.live. */ installed?: RHTNode; /** * `revived` is a tombstone this write replaced. It was registered as garbage * when it was removed, so the caller re-registers the pair to cancel that * registration: it is no longer collectable, it is simply gone. */ revived?: RHTNode; /** * `superseded` is a LIVE node this write replaced. RHT overrides immutably, * so the old node is dropped with no tombstone and nothing to collect, but * its bytes were counted in docSize.live and have to leave it. */ superseded?: RHTNode; }; /** * `RootStats` is a structure that represents the statistics of the root object. */ declare interface RootStats { /** * `elements` is the number of elements in the root object. */ elements?: number; /** * `gcElements` is the number of elements that can be garbage collected. */ gcElements?: number; /** * `gcPairs` is the number of garbage collection pairs. */ gcPairs?: number; } /** * @generated from message yorkie.v1.Rule */ declare type Rule_2 = Message<"yorkie.v1.Rule"> & { /** * @generated from field: string path = 1; */ path: string; /** * @generated from field: string type = 2; */ type: string; /** * @generated from field: repeated yorkie.v1.TreeNodeRule tree_nodes = 3; */ treeNodes: TreeNodeRule[]; }; /** * Definition of all messages the SDK can send to the Devtools panel. */ export declare 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. */ | { msg: 'doc::available'; docKey: string; } /** * Sent when a document the panel may be watching leaves the page: it * detached, or it was removed. The recording is kept, so the same key can * come back with `doc::available` when the document attaches again. */ | { msg: 'doc::unavailable'; docKey: string; } /** * Sent initially, to synchronize the entire current state of the document. */ | { msg: 'doc::sync::full'; docKey: string; events: Array; } /** * Sent whenever the document is changed. */ | { msg: 'doc::sync::partial'; docKey: string; event: DocEventsForReplay_2; } /** * Sent initially, to hand over the notifications recorded so far. These are * the events that cannot be replayed, so they travel beside the replay * stream instead of inside it. */ | { msg: 'doc::notification::full'; docKey: string; notifications: Array; } /** * Sent whenever an event that cannot be replayed occurs in the document. */ | { msg: 'doc::notification::partial'; docKey: string; notification: DocNotification_2; }; /** * `SessionLock` is a pluggable, single-active-session guard used by the offline * persistence path. Offline persistence derives a *stable* actor from the app's * clientKey, so two browser tabs of the same app+user share that actor. Two live * tabs would then share one server checkpoint and mint colliding `clientSeq` * values — silent edit loss. The guard elects a single active session per * document key so the second tab fails fast instead of corrupting the store. * * The abstraction is injectable so it can be tested without a real browser: the * default {@link WebLocksSessionLock} is backed by the Web Locks API, and tests * pass an in-memory fake. */ export declare interface SessionLock { /** * `acquire` tries to acquire the lock named `name` without waiting. It * resolves with a {@link SessionLockHandle} when the lock was acquired, or * `undefined` when it is already held elsewhere (e.g. by another tab) — the * caller treats `undefined` as fail-fast. */ acquire(name: string): Promise; } /** * `SessionLockHandle` represents an acquired, held session lock. It is held for * the lifetime of a document attachment and released on detach/deactivate. */ export declare interface SessionLockHandle { /** * `release` releases the held lock so a later tab can acquire it. It must be * idempotent: calling it more than once is a no-op. */ release(): void; } /** * `setLogLevel` sets log level. */ export declare function setLogLevel(l: LogLevel): void; /** * `SetOpInfo` represents the information of the set operation. */ export declare type SetOpInfo = { type: 'set'; path: string; key: string; }; /** * `SetOpInfo` represents the information of the set operation. */ declare type SetOpInfo_2 = { type: 'set'; path: string; key: string; }; /** * `SnapshotEvent` is an event that occurs when a snapshot is received from * the server. */ export declare interface SnapshotEvent extends BaseDocEvent_2 { type: DocEventType.Snapshot; source: OpSource.Remote; value: { snapshot: string | undefined; serverSeq: string; snapshotVector: string; }; } /** * `SnapshotEvent` is an event that occurs when a snapshot is received from * the server. */ declare interface SnapshotEvent_2 extends BaseDocEvent { type: DocEventType_2.Snapshot; source: OpSource_2.Remote; value: { snapshot: string | undefined; serverSeq: string; snapshotVector: string; }; } /** * `snapshotToBytes` converts the given root and presences into a byte array. * It is the reverse of `bytesToSnapshot`: the produced bytes decode back into * the same `{ root, presences }` shape via the shared `Snapshot` message. */ declare function snapshotToBytes

(root: CRDTObject, presences: Map): Uint8Array; /** * `SortedMapIterator` is a interator for traversing LLRBTree. */ declare class SortedMapIterator { stack: Array>; constructor(root: LLRBNode); private traverseInorder; } /** * `SplayNode` is a node of SplayTree. */ declare abstract class SplayNode { protected value: V; private left?; private right?; private parent?; private weight; constructor(value: V); abstract getLength(): number; /** * `getNodeString` returns a string of weight and value of this node. */ getNodeString(): string; /** * `getValue` returns value of this node. */ getValue(): V; /** * `getLeftWeight` returns left weight of this node. */ getLeftWeight(): number; /** * `getRightWeight` returns right weight of this node. */ getRightWeight(): number; /** * `getWeight` returns weight of this node. */ getWeight(): number; /** * `getLeft` returns a left node. */ getLeft(): SplayNode | undefined; /** * `getRight` returns a right node. */ getRight(): SplayNode | undefined; /** * `getParent` returns parent of this node. */ getParent(): SplayNode | undefined; /** * `hasLeft` check if the left node exists */ hasLeft(): boolean; /** * `hasRight` check if the right node exists */ hasRight(): boolean; /** * `hasParent` check if the parent node exists */ hasParent(): boolean; /** * `setLeft` sets a left node. */ setLeft(left?: SplayNode): void; /** * `setRight` sets a right node. */ setRight(right?: SplayNode): void; /** * `setParent` sets a parent node. */ setParent(parent?: SplayNode): void; /** * `unlink` unlink parent, right and left node. */ unlink(): void; /** * `hasLinks` checks if parent, right and left node exists. */ hasLinks(): boolean; /** * `increaseWeight` increases weight. */ increaseWeight(weight: number): void; /** * `initWeight` sets initial weight of this node. */ initWeight(): void; } /** * SplayTree is weighted binary search tree which is based on Splay tree. * original paper on Splay Trees: * @see https://www.cs.cmu.edu/~sleator/papers/self-adjusting.pdf */ declare class SplayTree { private root?; constructor(root?: SplayNode); /** * `length` returns the size of this tree. */ get length(): number; /** * `findForText` returns the Node and offset of the given position (cursor). * Used for Text where cursor placed between characters. */ findForText(pos: number): [SplayNode | undefined, number]; /** * `findForArray` returns the Node of the given position (index). * Used for Array where index points to the element. */ findForArray(idx: number): SplayNode | undefined; /** * Find the index of the given node in BST. * * @param node - the given node * @returns the index of given node */ indexOf(node: SplayNode): number; /** * `getRoot` returns root of this tree. */ getRoot(): SplayNode; /** * `insert` inserts the node at the last. */ insert(newNode: SplayNode): SplayNode; /** * `insertAfter` inserts the node after the given previous node. */ insertAfter(target: SplayNode | undefined, newNode: SplayNode): SplayNode; /** * `updateWeight` recalculates the weight of this node with the value and children. */ updateWeight(node: SplayNode): void; private updateTreeWeight; /** * `splayNode` moves the given node to the root. */ splayNode(node: SplayNode | undefined): void; /** * `delete` deletes target node of this tree. */ delete(node: SplayNode): void; /** * `deleteRange` separates the range between given 2 boundaries from this Tree. * This function separates the range to delete as a subtree * by splaying outer boundary nodes. * leftBoundary must exist because of 0-indexed initial dummy node of tree, * but rightBoundary can be nil means range to delete includes the end of tree. * Refer to the design document in https://github.com/yorkie-team/yorkie/tree/main/design */ deleteRange(leftBoundary: SplayNode, rightBoundary: SplayNode | undefined): void; private cutOffRight; /** * `toTestString` returns a string containing the meta data of the Node * for debugging purpose. */ toTestString(): string; /** * `checkWeight` returns false when there is an incorrect weight node. * for debugging purpose. */ checkWeight(): boolean; private getRightmost; private traverseInorder; private traversePostorder; private rotateLeft; private rotateRight; private isLeftChild; private isRightChild; } /** * `StatusChangedEvent` is an event that occurs when the status of a document changes. */ declare interface StatusChangedEvent extends BaseDocEvent { type: DocEventType_2.StatusChanged; source: OpSource_2; value: | { status: DocStatus_2.Attached; actorID: string } | { status: DocStatus_2.Detached } | { status: DocStatus_2.Removed }; } /** * `StatusChangedEvent` is an event that occurs when the status of a document changes. */ declare interface StatusChangedEvent_2 extends BaseDocEvent_2 { type: DocEventType.StatusChanged; source: OpSource; value: { status: DocStatus.Attached; actorID: string; } | { status: DocStatus.Detached; } | { status: DocStatus.Removed; }; } /** * `StoredChange` is one persisted local change, tagged with the `clientSeq` it * carries. The sequence is what lets a store drop changes a sync has already * acknowledged, and what lets a restore detect a hole rather than replaying a * discontinuous run. */ export declare interface StoredChange { clientSeq: number; bytes: Uint8Array; } /** * `StoredDoc` is everything a backend holds for one document: a base snapshot, * the changes appended since it, and a small mutable header. */ export declare interface StoredDoc { /** A `Document.toBytes()` envelope. */ snapshot: Uint8Array; /** * Checkpoint and changeID as of the last sync. Absent until the first one. * Held apart from the snapshot because a sync has to advance it constantly * while the snapshot stays put. */ meta?: Uint8Array; /** Changes appended since the snapshot, ascending by `clientSeq`. */ changes: Array; } /** * `StreamConnectionStatus` represents whether the stream connection is connected or not. */ export declare enum StreamConnectionStatus { /** * `Connected` means that the stream connection is connected. */ Connected = "connected", /** * `Disconnected` means that the stream connection is disconnected. */ Disconnected = "disconnected" } /** * `StreamConnectionStatus` represents whether the stream connection is connected or not. */ declare enum StreamConnectionStatus_2 { /** * `Connected` means that the stream connection is connected. */ Connected = 'connected', /** * `Disconnected` means that the stream connection is disconnected. */ Disconnected = 'disconnected', } /** * `StyleOpInfo` represents the information of the style operation. */ export declare type StyleOpInfo = { type: 'style'; path: string; from: number; to: number; value: { attributes: Indexable; }; }; /** * `StyleOpInfo` represents the information of the style operation. */ declare type StyleOpInfo_2 = { type: 'style'; path: string; from: number; to: number; value: { attributes: Indexable_2; }; }; declare interface SubscribeFn { (next: Observer | NextFn, error?: ErrorFn, complete?: CompleteFn): Unsubscribe; (observer: Observer): Unsubscribe; } /** * `SyncErrorEvent` represents a non-recoverable sync (RefreshChannel) error. * It carries the underlying error object so subscribers can inspect codes * (e.g. via `isErrorCode`) without losing the original Error. */ declare interface SyncErrorEvent { /** * `type` is the type of the event. */ type: ChannelEventType.SyncError; /** * `error` is the underlying error thrown by the RPC call. */ error: unknown; /** * `method` is the RPC method that failed (e.g. `RefreshChannel`). */ method: string; } /** * `SyncMode` defines synchronization modes for the PushPullChanges API * (documents) and the RefreshChannel heartbeat (channels). */ export declare enum SyncMode { /** * `Manual` mode indicates that changes are not automatically pushed or pulled. */ Manual = "manual", /** * `Realtime` mode indicates that changes are automatically pushed and pulled. */ Realtime = "realtime", /** * `RealtimePushOnly` mode indicates that only local changes are automatically pushed. * * The reply to a push-only request is taken as a push ack only: its * client-seq acknowledgement and pack metadata, never remote state and never * its version vector. Garbage-collecting with that vector would purge * tombstones that the remote changes this document has not pulled yet may * anchor on, leaving them unapplicable once it resumes pulling. */ RealtimePushOnly = "realtime-pushonly", /** * `RealtimeSyncOff` mode indicates that changes are not automatically pushed or pulled, * but the watch stream is kept active. */ RealtimeSyncOff = "realtime-syncoff", /** * `Polling` mode runs the sync loop without opening a watch stream. * - For Channel: heartbeat refreshes TTL and brings sessionCount. * - For Document: PushPullChanges runs at the polling interval. Remote * changes arrive on the next tick (latency = interval). Not suitable * for collaborative editing — use Realtime for that. */ Polling = "polling" } /** * `SyncStatusChangedEvent` is an event that occurs when document is synced with the server. */ export declare interface SyncStatusChangedEvent extends BaseDocEvent_2 { type: DocEventType.SyncStatusChanged; value: DocSyncStatus; } /** * `SyncStatusChangedEvent` is an event that occurs when document is synced with the server. */ declare interface SyncStatusChangedEvent_2 extends BaseDocEvent { type: DocEventType_2.SyncStatusChanged; value: DocSyncStatus_2; } /** * `teardownDevtools` releases what `setupDevtools` registered for the given * Document: its subscription, its window listener and its recording. Call it * when the Document is discarded — nothing else reaches those, and a page that * rebuilds Documents under one key accumulates them otherwise. It is a no-op * for a Document that has no devtools registration, and calling it twice is * harmless. */ export declare function teardownDevtools(doc: Document_2): void; /** * `Text` is an extended data type for the contents of a text editor. */ declare class Text_2 { private context?; private text?; constructor(context?: ChangeContext, text?: CRDTText); /** * `initialize` initialize this text with context and internal text. */ initialize(context: ChangeContext, text: CRDTText): void; /** * `getID` returns the ID of this text. */ getID(): TimeTicket; /** * `edit` edits this text with the given content. * An index inside a UTF-16 surrogate pair throws `ErrInvalidArgument`, and * so does content holding a lone half of one. */ edit(fromIdx: number, toIdx: number, content: string, attributes?: A): [number, number] | undefined; /** * `delete` deletes the text in the given range. */ delete(fromIdx: number, toIdx: number): [number, number] | undefined; /** * `empty` makes the text empty. */ empty(): [number, number] | undefined; /** * `setStyle` styles this text with the given attributes. * An index inside a UTF-16 surrogate pair throws `ErrInvalidArgument`. */ setStyle(fromIdx: number, toIdx: number, attributes: A): boolean; /** * `indexRangeToPosRange` returns TextRangeStruct of the given index range. */ indexRangeToPosRange(range: [number, number]): TextPosStructRange; /** * `posRangeToIndexRange` returns indexes of the given TextRangeStruct. */ posRangeToIndexRange(range: TextPosStructRange): [number, number]; /** * `toTestString` returns a String containing the meta data of the node * for debugging purpose. */ toTestString(): string; /** * `values` returns values of this text. */ values(): Array>; /** * `length` returns size of RGATreeList. */ get length(): number; /** * `getTreeByIndex` returns IndexTree of the text for testing purpose. */ getTreeByIndex(): SplayTree; /** * `getTreeByID` returns IDTree of the text for testing purpose. */ getTreeByID(): LLRBTree>; /** * `toString` returns the string representation of this text. */ toString(): string; /** * `toJSON` returns the JSON string of this tree. */ toJSON(): string; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `createRangeForTest` returns pair of RGATreeSplitNodePos of the given indexes * for testing purpose. * Unlike `CRDTText.createRange`, it does not reject an index inside a * surrogate pair. */ createRangeForTest(fromIdx: number, toIdx: number): RGATreeSplitPosRange; } export { Text_2 as Text } /** * `TextChange` represents the changes to the text * when executing the edit, setstyle methods. */ declare interface TextChange extends ValueChange> { type: TextChangeType; } /** * `TextChangeType` is the type of TextChange. * */ declare enum TextChangeType { Content = "content", Style = "style" } /** * `TextNode` represents a text node. It has a string value. */ export declare type TextNode = { type: typeof DefaultTextType_2; value: string; }; /** * `TextNode` represents a text node. It has a string value. */ declare type TextNode_2 = { type: typeof DefaultTextType; value: string; }; /** * @generated from message yorkie.v1.TextNodePos */ declare type TextNodePos = Message<"yorkie.v1.TextNodePos"> & { /** * @generated from field: yorkie.v1.TimeTicket created_at = 1; */ createdAt?: TimeTicket_2; /** * @generated from field: int32 offset = 2; */ offset: number; /** * @generated from field: int32 relative_offset = 3; */ relativeOffset: number; }; /** * `TextOpInfo` represents the OperationInfo for the yorkie.Text. */ export declare type TextOpInfo = EditOpInfo | StyleOpInfo; /** * `TextOpInfo` represents the OperationInfo for the yorkie.Text. */ declare type TextOpInfo_2 = EditOpInfo_2 | StyleOpInfo_2; /** * `TextPosStruct` represents the structure of RGATreeSplitPos. * It is used to serialize and deserialize the RGATreeSplitPos. */ export declare type TextPosStruct = { id: { createdAt: TimeTicketStruct; offset: number; }; relativeOffset: number; }; /** * `TextPosStructRange` represents the structure of RGATreeSplitPosRange. * It is used to serialize and deserialize the RGATreeSplitPosRange. */ export declare type TextPosStructRange = [TextPosStruct, TextPosStruct]; /** * `textToString` extracts plain text content from YSONText. * * @param text - YSONText object * @returns Plain text string * * @example * ```typescript * const text = { type: 'Text', nodes: [{val: 'H'}, {val: 'i'}] }; * textToString(text); // "Hi" * ``` */ declare function textToString(text: YSONText): string { return text.nodes.map((node) => node.val).join(''); } /** * `TextValueType` is a value of Text * which has a attributes that expresses the text style. */ declare interface TextValueType { attributes?: A; content?: string; } /** * `TimeTicket` is a timestamp of the logical clock. Ticket is immutable. * It is created by `ChangeID`. */ export declare class TimeTicket { private lamport; private delimiter; private actorID; constructor(lamport: bigint, delimiter: number, actorID: string); /** * `of` creates an instance of Ticket. */ static of(lamport: bigint, delimiter: number, actorID: string): TimeTicket; /** * `fromStruct` creates an instance of Ticket from the struct. */ static fromStruct(struct: TimeTicketStruct): TimeTicket; /** * `toIDString` returns the lamport string for this Ticket. */ toIDString(): string; /** * `toStruct` returns the structure of this Ticket. */ toStruct(): TimeTicketStruct; /** * `toTestString` returns a string containing the meta data of the ticket * for debugging purpose. */ toTestString(): string; /** * `setActor` creates a new instance of Ticket with the given actorID. */ setActor(actorID: ActorID): TimeTicket; /** * `getLamportAsString` returns the lamport string. */ getLamportAsString(): string; /** * `getLamport` returns the lamport. */ getLamport(): bigint; /** * `getDelimiter` returns delimiter. */ getDelimiter(): number; /** * `getActorID` returns actorID. */ getActorID(): string; /** * `after` returns whether the given ticket was created later. */ after(other: TimeTicket): boolean; /** * `equals` returns whether the given ticket was created. */ equals(other: TimeTicket): boolean; /** * `compare` returns an integer comparing two Ticket. * The result will be 0 if id==other, -1 if `id < other`, and +1 if `id > other`. * If the receiver or argument is nil, it would panic at runtime. */ compare(other: TimeTicket): number; } /** * @generated from message yorkie.v1.TimeTicket */ declare type TimeTicket_2 = Message<"yorkie.v1.TimeTicket"> & { /** * @generated from field: int64 lamport = 1; */ lamport: bigint; /** * @generated from field: uint32 delimiter = 2; */ delimiter: number; /** * @generated from field: bytes actor_id = 3; */ actorId: Uint8Array; }; /** * `TimeTicketStruct` is a structure represents the meta data of the ticket. * It is used to serialize and deserialize the ticket. */ export declare type TimeTicketStruct = { lamport: string; delimiter: number; actorID: ActorID; }; /** * `TimeTicketStruct` is a structure represents the meta data of the ticket. * It is used to serialize and deserialize the ticket. */ declare type TimeTicketStruct_2 = { lamport: string; delimiter: number; actorID: ActorID_2; }; /** * `toChangeID` converts the given model to Protobuf format. */ declare function toChangeID(changeID: ChangeID): ChangeID_2; /** * `toChangePack` converts the given model to Protobuf format. */ declare function toChangePack(pack: ChangePack): ChangePack_2; /** * `toHexString` converts the given byte array to hex string. */ declare function toHexString(bytes: Uint8Array): string; /** * `TokenType` represents the type of token in XML representation. */ declare 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" } /** * `toOperation` converts the given model to Protobuf format. */ declare function toOperation(operation: Operation): Operation_2; /** * `toRevisionSummary` converts a protobuf RevisionSummary to a RevisionSummary. */ declare function toRevisionSummary(pbRevision: RevisionSummary_2): RevisionSummary; /** * `toTreeNodes` converts the given model to Protobuf format. */ declare function toTreeNodes(node: CRDTTreeNode): Array; /** * `toUnit8Array` converts the given hex string to byte array. */ declare function toUint8Array(hex: string): Uint8Array; /** * `Tree` is a CRDT-based tree structure that is used to represent the document * tree of text-based editor such as ProseMirror. */ export declare class Tree { private initialRoot?; private context?; private tree?; constructor(initialRoot?: ElementNode); /** * `initialize` initialize this tree with context and internal tree. */ initialize(context: ChangeContext, tree: CRDTTree): void; /** * `getID` returns the ID of this tree. */ getID(): TimeTicket; /** * `buildRoot` builds the root of this tree with the given initial root * which set by the user. */ buildRoot(context: ChangeContext): CRDTTreeNode; /** * `getSize` returns the size of this tree. */ getSize(): number; /** * `getNodeSize` returns the node size of this tree. */ getNodeSize(): number; /** * `getIndexTree` returns the index tree of this tree. */ getIndexTree(): IndexTree; /** * `splitByPath` splits the tree by the given path. * A path whose text offset falls inside a UTF-16 surrogate pair throws * `ErrInvalidArgument`. */ splitByPath(path: Array): void; /** * `mergeByPath` merges the tree by the given path. */ mergeByPath(path: Array): void; /** * `styleByPath` sets the attributes to the element at the given * path. */ styleByPath(path: Array, attributes: { [key: string]: any; }): void; /** * `styleByPath` sets the attributes to the elements in the given * path range. */ styleByPath(fromPath: Array, toPath: Array, attributes: { [key: string]: any; }): void; /** * `style` sets the attributes to the elements of the given range. * An index inside a UTF-16 surrogate pair throws `ErrInvalidArgument`. */ style(fromIdx: number, toIdx: number, attributes: { [key: string]: any; }): void; /** * `removeStyle` removes the attributes to the elements of the given range. * An index inside a UTF-16 surrogate pair throws `ErrInvalidArgument`. */ removeStyle(fromIdx: number, toIdx: number, attributesToRemove: Array): void; /** * `removeStyleByPath` removes the attributes of the elements in * the given path range. * A path whose text offset falls inside a UTF-16 surrogate pair throws * `ErrInvalidArgument`. */ removeStyleByPath(fromPath: Array, toPath: Array, attributesToRemove: Array): void; private editInternal; /** * `editByPath` edits this tree with the given node and path. * A path whose text offset falls inside a UTF-16 surrogate pair throws * `ErrInvalidArgument`. */ editByPath(fromPath: Array, toPath: Array, content?: TreeNode, splitLevel?: number): boolean; /** * `editBulkByPath` edits this tree with the given node and path. * A path whose text offset falls inside a UTF-16 surrogate pair throws * `ErrInvalidArgument`. */ editBulkByPath(fromPath: Array, toPath: Array, contents: Array, splitLevel?: number): boolean; /** * `edit` edits this tree with the given nodes. * An index inside a UTF-16 surrogate pair throws `ErrInvalidArgument`. */ edit(fromIdx: number, toIdx: number, content?: TreeNode, splitLevel?: number): boolean; /** * `editBulk` edits this tree with the given nodes. * An index inside a UTF-16 surrogate pair throws `ErrInvalidArgument`. */ editBulk(fromIdx: number, toIdx: number, contents: Array, splitLevel?: number): boolean; /** * `toXML` returns the XML string of this tree. */ toXML(): string; /** * `toJSON` returns the JSON string of this tree. */ toJSON(): string; /** * `toJSForTest` returns value with meta data for testing. */ toJSForTest(): Devtools.JSONElement; /** * `toJSInfoForTest` returns detailed TreeNode information for use in Devtools. */ toJSInfoForTest(): Devtools.TreeNodeInfo; /** * `getRootTreeNode` returns TreeNode of this tree. */ getRootTreeNode(): TreeNode; /** * `indexToPath` returns the path of the given index. */ indexToPath(index: number): Array; /** * `pathToIndex` returns the index of given path. */ pathToIndex(path: Array): number; /** * `pathRangeToPosRange` converts the path range into the position range. */ pathRangeToPosRange(range: [Array, Array]): TreePosStructRange; /** * `indexRangeToPosRange` converts the index range into the position range. */ indexRangeToPosRange(range: [number, number]): TreePosStructRange; /** * `posRangeToIndexRange` converts the position range into the index range. */ posRangeToIndexRange(range: TreePosStructRange): [number, number]; /** * `posRangeToPathRange` converts the position range into the path range. */ posRangeToPathRange(range: TreePosStructRange): [Array, Array]; /** * `registerPendingGCPairs` registers with the root any GC pairs the tree * buffered while resolving a position. `posRangeToIndexRange` and * `posRangeToPathRange` split text nodes to locate a position; when the * position lands inside a tombstoned node the split produces a * born-removed piece. Unlike edit/style/removeStyle, these read-path * conversions emit no operation, so the buffered pairs would otherwise * never reach the root and the piece would leak (invisible to GC). */ private registerPendingGCPairs; } /** * `TreeChange` represents the change in the tree. */ export declare type TreeChange = { actor: ActorID; type: TreeChangeType.Content; from: number; to: number; fromPath: Array; toPath: Array; value?: Array; splitLevel?: number; } | { actor: ActorID; type: TreeChangeType.Style; from: number; to: number; fromPath: Array; toPath: Array; value: { [key: string]: string; }; splitLevel?: number; } | { actor: ActorID; type: TreeChangeType.RemoveStyle; from: number; to: number; fromPath: Array; toPath: Array; value?: Array; splitLevel?: number; }; /** * `TreeChangeType` represents the type of change in the tree. */ export declare enum TreeChangeType { Content = "content", Style = "style", RemoveStyle = "removeStyle" } /** * `TreeEditOpInfo` represents the information of the tree edit operation. */ export declare type TreeEditOpInfo = { type: 'tree-edit'; path: string; from: number; to: number; value?: Array; splitLevel?: number; fromPath: Array; toPath: Array; }; /** * `TreeEditOpInfo` represents the information of the tree edit operation. */ declare type TreeEditOpInfo_2 = { type: 'tree-edit'; path: string; from: number; to: number; value?: Array; splitLevel?: number; fromPath: Array; toPath: Array; }; /** * `TreeNode` represents a node in the tree. */ export declare type TreeNode = TextNode | ElementNode; /** * `TreeNode` represents a node in the tree. */ declare type TreeNode_2 = TextNode_2 | ElementNode_2; /** * @generated from message yorkie.v1.TreeNode */ declare type TreeNode_3 = Message<"yorkie.v1.TreeNode"> & { /** * @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_2; /** * @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; }; /** * merged_from is set when this node was moved to a new parent by a * concurrent merge. It points to the source parent's ID. * * @generated from field: yorkie.v1.TreeNodeID merged_from = 9; */ mergedFrom?: TreeNodeID; /** * merged_at records the immutable ticket of the merge operation. * Stored alongside merged_from because the source parent's removed_at * may be overwritten by later LWW tombstones and thus cannot serve as * the merge-time causal boundary for SplitElement. See * docs/design/concurrent-merge-split.md for details. * * @generated from field: yorkie.v1.TimeTicket merged_at = 10; */ mergedAt?: TimeTicket_2; }; /** * `TreeNodeForTest` represents the JSON representation of a node in the tree. * It is used for testing. */ declare type TreeNodeForTest = TreeNode & { children?: Array; visibleSize: number; isRemoved: boolean; }; /** * @generated from message yorkie.v1.TreeNodeID */ declare type TreeNodeID = Message<"yorkie.v1.TreeNodeID"> & { /** * @generated from field: yorkie.v1.TimeTicket created_at = 1; */ createdAt?: TimeTicket_2; /** * @generated from field: int32 offset = 2; */ offset: number; }; /** * `TreeNodeInfo` represents the crdt tree node information in devtools. */ declare type TreeNodeInfo = { id: string; type: string; parent?: string; size: number; value?: string; removedAt?: string; isRemoved: boolean; insPrev?: string; insNext?: string; children: Array; attributes?: object; // TODO(chacha912): Specify the type accurately. depth: number; index?: number; path?: Array; pos?: CRDTTreePosStruct; }; /** * `TreeNodePair` represents a pair of CRDTTreeNode. It represents the position * of the node in the tree with the left and parent nodes. */ declare type TreeNodePair = [CRDTTreeNode, CRDTTreeNode]; /** * @generated from message yorkie.v1.TreeNodeRule */ declare type TreeNodeRule = Message<"yorkie.v1.TreeNodeRule"> & { /** * @generated from field: string node_type = 1; */ nodeType: string; /** * @generated from field: string content = 2; */ content: string; /** * @generated from field: string marks = 3; */ marks: string; /** * @generated from field: string group = 4; */ group: string; }; /** * @generated from message yorkie.v1.TreeNodes */ declare type TreeNodes = Message<"yorkie.v1.TreeNodes"> & { /** * @generated from field: repeated yorkie.v1.TreeNode content = 1; */ content: TreeNode_3[]; }; /** * `NoteType` is the type of a node in the tree. */ declare type TreeNodeType = string; /** * `NoteType` is the type of a node in the tree. */ declare type TreeNodeType_2 = string; /** * `TreeOpInfo` represents the OperationInfo for the yorkie.Tree. */ export declare type TreeOpInfo = TreeEditOpInfo | TreeStyleOpInfo; /** * `TreeOpInfo` represents the OperationInfo for the yorkie.Tree. */ declare type TreeOpInfo_2 = TreeEditOpInfo_2 | TreeStyleOpInfo_2; /** * `TreePos` is the position of a node in the tree. * * `offset` is the position of node's token. For example, if the node is an * element node, the offset is the index of the child node. If the node is a * text node, the offset is the index of the character. */ declare type TreePos> = { node: T; offset: number; }; /** * @generated from message yorkie.v1.TreePos */ declare type TreePos_2 = Message<"yorkie.v1.TreePos"> & { /** * @generated from field: yorkie.v1.TreeNodeID parent_id = 1; */ parentId?: TreeNodeID; /** * @generated from field: yorkie.v1.TreeNodeID left_sibling_id = 2; */ leftSiblingId?: TreeNodeID; }; /** * `TreePosRange` represents a pair of CRDTTreePos. */ declare type TreePosRange = [CRDTTreePos, CRDTTreePos]; /** * `TreePosStructRange` represents the structure of TreeRange. * It is used to serialize and deserialize the TreeRange. */ export declare type TreePosStructRange = [CRDTTreePosStruct_2, CRDTTreePosStruct_2]; /** * `TreeRestoreSpan` identifies a node this edit transitioned * visible → tombstoned, for identity-preserving Tree undo/redo. For text * nodes the span is the absolute-offset interval [id.offset, id.offset + * length) of the original insertion (split-invariant); for element nodes it * is the whole node. `value`/`attrs` are deep-copied so a GC-purged node can * be recreated. `leftSiblingID`/`rightSiblingID` are the deleted run's * external boundary anchors captured at tombstone time — redundant on * purpose: since a run's spans are carried together, restore can rebuild the * run's internal order from the op itself and needs only ONE surviving * boundary to place it (id-order is not sibling-order in a tree). */ declare type TreeRestoreSpan = { id: CRDTTreeNodeID; nodeType: string; isText: boolean; length: number; value?: string; attrs?: RHT; parentID?: CRDTTreeNodeID; leftSiblingID?: CRDTTreeNodeID; rightSiblingID?: CRDTTreeNodeID; }; /** * TreeRestoreSpan carries a tree node run from a single deletion, addressed * by TreeNodeID identity, for identity-preserving Tree undo/redo. Unlike the * text RestoreSpan (flat offsets), a tree span records the node's structure * (type/attrs) and its position anchors, because in a tree id-order is not * sibling-order: left_sibling_id and right_sibling_id are redundant external * boundary anchors of the deleted run, so restore can reconstruct the run's * internal order from the op's own spans and needs only one surviving * boundary to place it. value/attributes are a deep copy so a GC-purged node * can be recreated. * * @generated from message yorkie.v1.TreeRestoreSpan */ declare type TreeRestoreSpan_2 = Message<"yorkie.v1.TreeRestoreSpan"> & { /** * @generated from field: yorkie.v1.TreeNodeID id = 1; */ id?: TreeNodeID; /** * @generated from field: string node_type = 2; */ nodeType: string; /** * @generated from field: bool is_text = 3; */ isText: boolean; /** * @generated from field: int32 length = 4; */ length: number; /** * @generated from field: string value = 5; */ value: string; /** * @generated from field: map attributes = 6; */ attributes: { [key: string]: NodeAttr; }; /** * @generated from field: yorkie.v1.TreeNodeID parent_id = 7; */ parentId?: TreeNodeID; /** * @generated from field: yorkie.v1.TreeNodeID left_sibling_id = 8; */ leftSiblingId?: TreeNodeID; /** * @generated from field: yorkie.v1.TreeNodeID right_sibling_id = 9; */ rightSiblingId?: TreeNodeID; }; /** * `TreeStyleOpInfo` represents the information of the tree style operation. */ export declare type TreeStyleOpInfo = { type: 'tree-style'; path: string; from: number; to: number; fromPath: Array; toPath: Array; value: { attributes?: Indexable; attributesToRemove?: Array; }; }; /** * `TreeStyleOpInfo` represents the information of the tree style operation. */ declare type TreeStyleOpInfo_2 = { type: 'tree-style'; path: string; from: number; to: number; fromPath: Array; toPath: Array; value: { attributes?: Indexable_2; attributesToRemove?: Array; }; }; /** * `TreeToken` represents the token of the tree in XML representation. */ declare type TreeToken = [T, TokenType]; /** * `treeToXML` converts YSONTree to XML string representation. * * @param tree - YSONTree object * @returns XML string */ declare function treeToXML(tree: YSONTree): string { return treeNodeToXML(tree.root); } /** * `TreeVisibleEdit` is a content change an identity-preserving restore or * retombstone made, paired with the visible size it inserted (zero for a * deletion). The change alone does not carry that size — an insertion reports * a collapsed range — and undo-stack reconciliation cannot shift the pending * indices without it. */ declare type TreeVisibleEdit = { change: TreeChange; insertedSize: number; }; export declare type Unsubscribe = () => void; export declare interface UnwatchedEvent

extends BaseDocEvent_2 { type: DocEventType.Unwatched; source: OpSource.Remote; value: { clientID: ActorID; presence: P; }; } declare interface UnwatchedEvent_2

extends BaseDocEvent { type: DocEventType_2.Unwatched; source: OpSource_2.Remote; value: { clientID: ActorID_2; presence: P }; } declare interface ValueChange { actor: ActorID; from: number; to: number; value?: T; } /** * @generated from enum yorkie.v1.ValueType */ 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, /** * @generated from enum value: VALUE_TYPE_INTEGER_DEDUP_CNT = 14; */ INTEGER_DEDUP_CNT = 14 } /** * `VersionVector` is a vector clock that is used to detect the relationship * between changes whether they are causally related or concurrent. It is * similar to vector clocks, but it is synced with lamport timestamp of the * change. */ export declare class VersionVector { private vector; constructor(vector?: Map); /** * `set` sets the lamport timestamp of the given actor. */ set(actorID: string, lamport: bigint): void; /** * `unset` removes the version for the given actor from the VersionVector. */ unset(actorID: string): void; /** * `get` gets the lamport timestamp of the given actor. */ get(actorID: string): bigint | undefined; /** * `has` checks if the given actor exists in the VersionVector. */ has(actorID: string): boolean; /** * `maxLamport` returns max lamport value from vector */ maxLamport(): bigint; /** * `max` returns new version vector which consists of max value of each vector */ max(other: VersionVector): VersionVector; /** * `afterOrEqual` returns vector[other.actorID] is greaterOrEqual than given ticket's lamport */ afterOrEqual(other: TimeTicket): boolean; /** * `deepcopy` returns a deep copy of this `VersionVector`. */ deepcopy(): VersionVector; /** * `filter` returns new version vector consist of filter's actorID. */ filter(versionVector: VersionVector): VersionVector; /** * `size` returns size of version vector */ size(): number; [Symbol.iterator](): IterableIterator<[string, bigint]>; } /** * @generated from message yorkie.v1.VersionVector */ declare type VersionVector_2 = Message<"yorkie.v1.VersionVector"> & { /** * @generated from field: map vector = 1; */ vector: { [key: string]: bigint; }; }; /** * `versionVectorToHex` converts the given VersionVector to bytes. */ declare function versionVectorToHex(vector: VersionVector): string; export declare interface WatchedEvent

extends BaseDocEvent_2 { type: DocEventType.Watched; source: OpSource.Remote; value: { clientID: ActorID; presence: P; }; } declare interface WatchedEvent_2

extends BaseDocEvent { type: DocEventType_2.Watched; source: OpSource_2.Remote; value: { clientID: ActorID_2; presence: P }; } /** * `WebLocksSessionLock` is the default {@link SessionLock}, backed by the Web * Locks API (`navigator.locks.request` with `{ ifAvailable: true }`). * * A Web Lock is held for as long as the promise returned from the request's * callback stays pending. To hold the lock for the whole attachment lifetime, * `acquire` keeps that callback pending on a promise that only resolves when the * returned handle's `release` is called. When the lock is already held (another * tab), `ifAvailable` invokes the callback with a `null` lock and `acquire` * resolves `undefined` — the fail-fast signal. * * When the Web Locks API is unavailable (non-browser runtimes), this is a no-op: * `acquire` always resolves a handle whose `release` does nothing, so it never * breaks non-browser usage. Multi-tab safety simply does not apply there. */ export declare class WebLocksSessionLock implements SessionLock { /** * `acquire` acquires the named lock without waiting, or resolves `undefined` * when it is already held elsewhere. */ acquire(name: string): Promise; } /** * `WrappedElement` is a wrapper of JSONElement that provides `getID()`. */ export declare type WrappedElement = Primitive | JSONObject | JSONArray | Text_2 | Counter | DedupCounter | Tree; /** * `YorkieError` is an error returned by a Yorkie operation. */ export declare class YorkieError extends Error { readonly code: Code; readonly message: string; name: string; stack?: string; constructor(code: Code, message: string); } declare namespace YSON { export { YSONValue, YSONText as Text, YSONTree as Tree, YSONTextNode as TextNode, YSONTreeNode as TreeNode, YSONInt as Int, YSONLong as Long, YSONDate as Date, YSONBinData as BinData, YSONCounter as Counter, YSONDedupCounter as DedupCounter, isText, isTree, isInt, isLong, isDate, isBinData, isCounter, isDedupCounter, isObject, parse, textToString, treeToXML } } export { YSON } /** * `YSONBinData` represents Base64-encoded binary data. * * @example * ```typescript * { type: 'BinData', value: 'AQID' } * ``` */ declare interface YSONBinData { type: 'BinData'; value: string; } /** * `YSONCounter` represents a Counter CRDT for collaborative counting. * * @example * ```typescript * { type: 'Counter', value: { type: 'Int', value: 10 } } * ``` */ declare interface YSONCounter { type: 'Counter'; value: YSONInt | YSONLong; } /** * `YSONDate` represents an ISO 8601 timestamp. * * @example * ```typescript * { type: 'Date', value: '2025-01-02T15:04:05.058Z' } * ``` */ declare interface YSONDate { type: 'Date'; value: string; } /** * `YSONDedupCounter` represents a DedupCounter CRDT that uses HyperLogLog * to count unique actors. * * @example * ```typescript * { type: 'DedupCounter', value: { type: 'Int', value: 15 }, registers: 'AQID...' } * ``` */ declare interface YSONDedupCounter { type: 'DedupCounter'; value: YSONInt; registers: string; } /** * `YSONInt` represents a 32-bit integer. * * @example * ```typescript * { type: 'Int', value: 42 } * ``` */ declare interface YSONInt { type: 'Int'; value: number; } /** * `YSONLong` represents a 64-bit integer. * * @example * ```typescript * { type: 'Long', value: 64 } * ``` */ declare interface YSONLong { type: 'Long'; value: number; } /** * `YSONText` represents a Text CRDT structure. * * @example * ```typescript * { * type: 'Text', * nodes: [ * { val: 'H' }, * { val: 'i' } * ] * } * ``` */ declare interface YSONText { type: 'Text'; nodes: Array; } /** * `YSONTextNode` represents a single character in a Text CRDT. * * @example * ```typescript * { val: 'H', attrs: { bold: true } } * ``` */ declare interface YSONTextNode { /** * The character value */ val: string; /** * Optional attributes (e.g., formatting) */ attrs?: Record; } /** * `YSONTree` represents a Tree CRDT structure. * * @example * ```typescript * { * type: 'Tree', * root: { * type: 'doc', * children: [ * { type: 'p', children: [{ type: 'text', value: 'Hello' }] } * ] * } * } * ``` */ declare interface YSONTree { type: 'Tree'; root: YSONTreeNode; } /** * `YSONTreeNode` represents a node in a Tree CRDT. * * For text nodes: `{ type: 'text', value: 'content' }` * For element nodes: `{ type: 'p', children: [...] }` */ declare interface YSONTreeNode { /** * Node type (e.g., 'text', 'p', 'div') */ type: string; /** * Text content (for text nodes) */ value?: string; /** * Attributes (for element nodes) */ attrs?: Record; /** * Child nodes (for element nodes) */ children?: Array; } /** * `YSONValue` represents any valid YSON value. * * Can be: * - Primitives: string, number, boolean, null * - Collections: arrays, objects * - CRDT types: Text, Tree, Counter * - Special types: Int, Long, Date, BinData */ declare type YSONValue = | string | number | boolean // eslint-disable-next-line @typescript-eslint/no-restricted-types | null | YSONText | YSONTree | YSONInt | YSONLong | YSONDate | YSONBinData | YSONCounter | YSONDedupCounter | { [key: string]: YSONValue } | Array; export { }