UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

191 lines (190 loc) 8.94 kB
import { Model } from '../model'; import { type ITimestampStruct, type Patch } from '../../json-crdt-patch'; import type { Printable } from 'tree-dump/lib/types'; import type { JsonNode } from '../nodes/types'; /** * The `Log` represents a history of patches applied to a JSON CRDT model. It * consists of: (1) a starting {@link Model} instance, (2) a list of {@link Patch} instances, * that can be applied to the starting model to reach the current state of the * document, and (3) the current state of the document, the `end` {@link Model}. * * The log can be used to replay the history of patches to any point in time, * from the "start" to the "end" of the log, and return the resulting {@link Model} * state. * * @todo Make this implement UILifecycle (start, stop) interface. */ export declare class Log<N extends JsonNode = JsonNode<any>, Metadata extends Record<string, unknown> = Record<string, unknown>> implements Printable { /** * Model factory function that creates a new JSON CRDT model instance, which * is used as the starting point of the log. It is called every time a new * model is needed to replay the log. * * @readonly Internally this function may be updated, but externally it is * read-only. * * @todo Rename to something else to give way to a `start()` in UILifecycle. * Call "snapshot". Maybe introduce `type Snapshot<N> = () => Model<N>;`. */ start: () => Model<N>; /** * The end of the log, the current state of the document. It is the model * instance that is used to apply new patches to the log. * * @readonly */ readonly end: Model<N>; /** * Creates a `PatchLog` instance from a newly JSON CRDT model. Checks if * the model API buffer has any initial operations applied, if yes, it * uses them to create the initial state of the log. * * @param model A new JSON CRDT model, just created with * `Model.create()` or `Model.withServerClock()`. * @returns A new `PatchLog` instance. */ static fromNewModel<N extends JsonNode = JsonNode<any>>(model: Model<N>): Log<N>; static from<N extends JsonNode = JsonNode<any>>(model: Model<N>): Log<N>; /** * Custom metadata associated with the log, it will be stored in the log's * header when serialized with {@link LogEncoder} and can be used to store * additional information about the log. */ metadata: Metadata; /** * The collection of patches which are applied to the `start()` model to reach * the `end` model. The patches in the log, stored in an AVL tree for * efficient replaying. The patches are sorted by their logical timestamps * and applied in causal order. * * @readonly */ patches: { min: import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; root: import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; max: import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; readonly comparator: import("sonic-forest/lib/types").Comparator<ITimestampStruct>; set(k: ITimestampStruct, v: Patch): import("sonic-forest/lib/types").SonicNodePublicReference<import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch>>; find(k: ITimestampStruct): import("sonic-forest/lib/types").SonicNodePublicReference<import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch>> | undefined; get(k: ITimestampStruct): Patch | undefined; del(k: ITimestampStruct): boolean; clear(): void; has(k: ITimestampStruct): boolean; _size: number; size(): number; isEmpty(): boolean; getOrNextLower(k: ITimestampStruct): import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; forEach(fn: (node: import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch>) => void): void; first(): import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; last(): import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; readonly next: <N_1 extends import("sonic-forest/lib/types").HeadlessNode>(curr: N_1) => N_1 | undefined; iterator0(): () => import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch> | undefined; iterator(): Iterator<import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch>, any, undefined>; entries(): IterableIterator<import("sonic-forest/lib/types").ITreeNode<ITimestampStruct, Patch>>; toString(tab: string): string; }; private __onPatch; private __onFlush; constructor( /** * Model factory function that creates a new JSON CRDT model instance, which * is used as the starting point of the log. It is called every time a new * model is needed to replay the log. * * @readonly Internally this function may be updated, but externally it is * read-only. * * @todo Rename to something else to give way to a `start()` in UILifecycle. * Call "snapshot". Maybe introduce `type Snapshot<N> = () => Model<N>;`. */ start: () => Model<N>, /** * The end of the log, the current state of the document. It is the model * instance that is used to apply new patches to the log. * * @readonly */ end?: Model<N>, metadata?: Metadata); /** * Call this method to destroy the {@link Log} instance. It unsubscribes patch * and flush listeners from the `end` model and clears the patch log. */ destroy(): void; /** * Creates a new model instance using the `start()` factory function and * replays all patches in the log to reach the current state of the document. * * @returns A new model instance with all patches replayed. */ replayToEnd(): Model<N>; /** * Replays the patch log until a specified timestamp, including the patch * at the given timestamp. The model returned is a new instance of `start()` * with patches replayed up to the given timestamp. * * @param ts Timestamp ID of the patch to replay to. * @param inclusive If `true`, the patch at the given timestamp `ts` is included, * otherwise replays up to the patch before the given timestamp. Default is `true`. * @returns A new model instance with patches replayed up to the given timestamp. */ replayTo(ts: ITimestampStruct, inclusive?: boolean): Model<N>; /** * Advance the start of the log to a specified timestamp, excluding the patch * at the given timestamp. This method removes all patches from the log that * are older than the given timestamp and updates the `start()` factory * function to replay the log from the new start. * * @param ts Timestamp ID of the patch to advance to. */ advanceTo(ts: ITimestampStruct): void; /** * Finds the latest patch for a given session ID. * * @param sid Session ID to find the latest patch for. * @return The latest patch for the given session ID, or `undefined` if no * such patch exists. */ findMax(sid: number): Patch | undefined; /** * @returns A deep clone of the log, including the start function, metadata, * patches, and the end model. */ clone(): Log<N, Metadata>; /** * Rebase a batch of patches on top of the current end of the log, or on top * of the latest patch for a given session ID. * * @param batch A batch of patches to rebase. * @param sid Session ID to find the latest patch for rebasing. If not provided, * the latest patch in the log is used. * @returns The rebased patches. */ rebaseBatch(batch: Patch[], sid?: number): Patch[]; /** * Resets the log to the state of another log. Consumes all state fron the `to` * log. The `to` log will be destroyed and should not be used after calling * this method. * * If you want to preserve the `to` log, use `.clone()` method first. * * ```ts * const log1 = new Log(); * const log2 = new Log(); * log1.reset(log2.clone()); * ``` * * @param to The log to consume the state from. */ reset(to: Log<N, Metadata>): void; /** * Creates a patch which reverts the given patch. The RGA insertion operations * are reversed just by deleting the inserted values. All other operations * require time travel to the state just before the patch was applied, so that * a copy of a mutated object can be created and inserted back into the model. * * @param patch The patch to undo * @returns A new patch that undoes the given patch */ undo(patch: Patch): Patch; toString(tab?: string): string; }