@yorkie-js/sdk
    Preparing search index...

    Class Document<R, P>

    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.

    Type Parameters

    Implements

    • Attachable
    Index

    Constructors

    Properties

    history: {
        canRedo: () => boolean;
        canUndo: () => boolean;
        redo: () => void;
        undo: () => void;
    }

    history is exposed to the user to manage undo/redo operations.

    Methods

    • Internal

      acknowledgePushedChanges removes the local changes the server has confirmed, and forwards only the client seq of the checkpoint. It is for a response pack dropped without applying its remote state: the server seq must stay put so the skipped state is pulled again later, while the confirmed changes must not be pushed again. The server dedupes a re-pushed change when storing it, but a snapshot it builds for the same request would apply that change a second time.

      The pack's metadata is not remote state, and is taken in full: the compaction epoch and the removal flag describe the document itself, not the content being skipped, and neither is re-sent by a later pull the way the skipped changes are.

      Parameters

      • pack: ChangePack<P>

      Returns 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.

      Parameters

      • clientSeq: number

      Returns 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.

      Parameters

      • pack: ChangePack<P>

      Returns void

    • applyDocEvent applies the given doc event into this document.

      Parameters

      • type: DocEventType
      • publisher: string

      Returns void

    • applySnapshot applies the given snapshot into this document.

      Parameters

      • serverSeq: bigint
      • snapshotVector: VersionVector
      • Optionalsnapshot: Uint8Array<ArrayBufferLike>
      • clientSeq: number = -1

      Returns void

    • applyWatchInit applies the watch initialization with the given client IDs.

      Parameters

      • clientIDs: string[]

      Returns 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.

      Returns void

    • discardLocalChanges takes the un-pushed local changes out of the queue and returns them. Used by Client.resync when the server has refused this client's writes: the queued changes would be re-sent and re-denied by every later sync, so the only way forward is to stop presenting them.

      The clientSeq counter is deliberately left where it is. The discarded changes already minted those sequences, and rewinding would mint them a second time — the hazard Document.advanceClientSeqTo exists to rule out: the server skips a clientSeq it has already taken as a duplicate, and the offline-persistence watermarks assume the counter only rises. The cost of not rewinding is that the queue now has a hole relative to the acked checkpoint, so no change may be minted before the document is re-anchored. That is not left to the caller to remember: the discard suspends minting outright, so update and undo/redo refuse with ErrRefused until the hole is closed. Client.resync spans several awaits — a detach that enqueues a task and does an RPC, then a re-attach — and the app keeps hold of the Document throughout, so without the suspension a single edit in that window either wedges the detach with ErrInvalidClientSeq or is wiped by resetForReanchor without ever appearing in the data-loss event. A loud refusal the app can catch is the one outcome that loses nothing. resync also detaches without the usual presence clear, so the recovery itself mints nothing.

      Only that window is closed. An edit landing before the discard is taken by it and reported in the data-loss event, and one landing after the re-anchor is ordinary pre-attach editing; neither is at risk.

      This does not undo the discarded changes on root: they are already applied and there is no server-confirmed copy to fall back on. The caller is expected to follow with resetForReanchor and a fresh attach, which replaces the local state with the server's — or, if that fails, to hand the changes back with Document.restoreLocalChanges. Both lift the suspension; they are the only two ways out of it.

      Returns Change<P>[]

    • 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).

      Returns string

    • getOthersForTest returns all the other clients in online, sorted by clientID.

      Returns { clientID: string; presence: P }[]

    • 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.

      Parameters

      • clientSeq: number

      Returns { clientSeq: number; struct: ChangeStruct<P> }[]

    • 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.

      Returns ChangeStruct<P>[]

    • getPresenceForTest returns the presence of the given clientID regardless of whether the client is online or not.

      Parameters

      • clientID: string

      Returns P | undefined

    • hasLocalChanges returns whether this document has local changes or not.

      Returns boolean

    • hasMintedOperations returns whether this document has produced a local change carrying operations, i.e. whether tickets naming its actor may already be in the document its key names. The client reads it to decide whether a re-issue -- which starts the actor's lamports back at 1 -- can still be sound for that key. See Client.claimReissue.

      Returns boolean

    • isMintable returns whether this document may queue a new local change. It is false only inside the re-anchor window discardLocalChanges opens, where update and undo/redo refuse with ErrRefused.

      It is public so that a caller which mints a change as a side effect of something else can ask instead of throwing out of an unrelated API: Client.detach mints a presence clear, and an unmount cleanup calling it has nowhere to put that exception. history.canUndo/canRedo read it for the same reason.

      Returns boolean

    • 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.

      Returns boolean

    • 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.

      Returns Uint8Array

    • 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.

      Returns void

    • resetPresenceBase drops the assumption that the server holds a base for us, so the next presence update is a full put. A reconnect -- including restoring a document from offline persistence -- has to do this: the server that answers next may never have seen our presence.

      Returns 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.

      Parameters

      • structs: ChangeStruct<P>[]
      • ackedClientSeq: number = 0

      Returns void

    • 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.

      Parameters

      • bytes: Uint8Array

      Returns void

    • restoreLocalChanges puts changes taken by discardLocalChanges back at the head of the queue, undoing the discard. It is the rollback for a recovery that could not go through: Client.resync restores the queue when the detach it needs is itself refused, so a failed recovery leaves the document exactly as it found it rather than with its edits destroyed.

      The restored changes are older than anything queued since, so they go in front; clientSeq is untouched because the discard never moved it.

      Putting them back closes the hole, so minting is allowed again — the document is left exactly as the discard found it, writable included.

      Parameters

      Returns void

    • restoreMetaFromBytes applies the bytes produced by metaToBytes, overwriting the checkpoint and changeID. Trailing blobs stay optional, the same extension rule the toBytes envelope follows.

      Parameters

      • bytes: Uint8Array

      Returns void

    • restorePresencePatches rewrites the earliest pending presence patch into a full put of the presence as of that change, leaving the later patches alone: the server folds them in order, so a put in front of them is the base they need. It answers ErrPresenceBaseUnavailable, where nothing in the rejected pack was stored and the whole pack is resent.

      Returns void

    • setActor sets actor into this document. This is also applied in the local changes the document has. It returns whether the tickets were re-issued.

      Without reissue it rewrites only the change IDs and each operation's executedAt; the root and the tickets inside the operations keep the actor they were minted under. With reissue, a never-synced document re-issues every ticket of its previous actor to the given one, so a position or element ID taken from it before then no longer resolves. See docs/design/pre-attach-ticket-reissue.md.

      reissue has to carry ReissueToken, which only the owning Client holds: rewriting element identity under a caller-chosen actor is not a capability a holder of this handle gets.

      Parameters

      • actorID: string
      • Optionalopts: SetActorOptions

      Returns boolean

    • setDisableGC records whether this document participates in GC. The client calls this on attach so subsequent applyChange runs use the lamport-only sync path.

      Parameters

      • disableGC: boolean

      Returns 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.

      Parameters

      • disablePresence: boolean

      Returns void

    • setDocID records the server-assigned document id so the next persisted envelope carries it for the Tier-3 silent-purge guard.

      Parameters

      • docID: string

      Returns void

    • Internal

      subscribeLocalChangesInternal observes newly queued local changes after the document state and changeID have been committed. It runs before public events so a subscriber-triggered sync cannot remove changes before the persistence layer captures them. Public events can be empty or suppressed.

      Parameters

      • callback: () => void

      Returns Unsubscribe

    • 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.

      Returns Uint8Array