history is exposed to the user to manage undo/redo operations.
InternalacknowledgePushedChanges 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.
addOnlineClient adds the given clientID into the online client set.
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.
applyChangePack applies the given change pack into this document.
applyDocEvent applies the given doc event into this document.
applyDocEventsForReplay applies the given events into this document.
applySnapshot applies the given snapshot into this document.
Optionalsnapshot: Uint8Array<ArrayBufferLike>applyWatchInit applies the watch initialization with the given client IDs.
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.
createChangePack create change pack of the local changes to send to the
remote server.
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.
ensureClone make a clone of root.
garbageCollect purges elements that were removed before the given time.
getChangeID returns the change id of this document.
getCheckpoint returns the checkpoint of this document.
getClone returns this clone.
getCloneRoot returns clone object.
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).
getDocSize returns the size of this document.
getEpoch returns the document's last-known compaction epoch.
getGarbageLen returns the length of elements should be purged.
getGarbageLenFromClone returns the length of elements should be purged from clone.
getKey returns the key of this document.
getMaxSizePerDocument gets the maximum size of this document.
getMyPresence returns the presence of the current client.
getOthersForTest returns all the other clients in online, sorted by clientID.
getOthersPresences returns the presences of all other clients.
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.
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.
getPresence returns the presence of the given clientID.
getPresenceForTest returns the presence of the given clientID
regardless of whether the client is online or not.
getPresences returns the presences of online clients.
getRedoStackForTest returns the redo stack for test.
getRoot returns a new proxy of cloned root.
getRootCRDT returns the CRDTRoot for testing purposes.
This method is intended for internal testing only.
getRootObject returns root object.
getSchemaRules gets the schema rules of this document.
getSelfForTest returns the client that has attached this document.
getStats returns the statistics of this document.
getStatus returns the status of this document.
getUndoStackForTest returns the undo stack for test.
getValueByPath returns the JSONElement corresponding to the given path.
getVersionVector returns the version vector of document
hasLocalChanges returns whether this document has local changes or not.
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.
hasPresence returns whether the given clientID has a presence or not.
isEnableDevtools returns whether devtools is enabled or not.
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.
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.
isPresencePatchableForTest returns whether the next presence update
would be recorded as a patch.
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.
removeOnlineClient removes the clientID from the online client set.
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.
resetOnlineClients resets the online client set.
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.
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.
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.
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.
restoreMetaFromBytes applies the bytes produced by metaToBytes,
overwriting the checkpoint and changeID. Trailing blobs stay optional, the
same extension rule the toBytes envelope follows.
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.
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.
Optionalopts: SetActorOptionssetDisableGC records whether this document participates in GC. The
client calls this on attach so subsequent applyChange runs use the
lamport-only sync path.
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.
setDocID records the server-assigned document id so the next persisted
envelope carries it for the Tier-3 silent-purge guard.
setMaxSizePerDocument sets the maximum size of this document.
setOnlineClients sets the given online client set.
setSchemaRules sets the schema rules of this document.
subscribe registers a callback to subscribe to events on the document.
The callback will be called when the document is changed.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe 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.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe registers a callback to subscribe to events on the document.
The callback will be called when the current client establishes or updates its presence.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe 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.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe registers a callback to subscribe to events on the document.
The callback will be called when the stream connection status changes.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe registers a callback to subscribe to events on the document.
The callback will be called when the document status changes.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe registers a callback to subscribe to events on the document.
The callback will be called when the document is synced with the server.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe 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.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnsubscribe registers a callback to subscribe to events on the document.
The callback will be called when the authentification error occurs.
subscribe registers a callback to subscribe to events on the document.
The callback will be called when an epoch mismatch error occurs.
Optionalerror: ErrorFnsubscribe registers a callback to subscribe to events on the document.
The callback will be called when the server rejects this document's
pushed changes for a reason that resending them cannot fix.
Optionalerror: ErrorFnsubscribe 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 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 registers a callback to subscribe to events on the document.
Optionalerror: ErrorFnOptionalcomplete: CompleteFnInternalsubscribeLocalChangesInternal 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.
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.
toJSForTest returns value with meta data for testing.
toJSON returns the JSON encoding of this document.
toSortedJSON returns the sorted JSON encoding of this document.
update executes the given updater to update this document.
Optionalmessage: stringStaticfrom
Documentis 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.