import { ObjNode, ArrNode, BinNode, ConNode, VecNode, ValNode, StrNode, RootNode } from '../../nodes'; import { NodeEvents } from './NodeEvents'; import { FanOut, type FanOutUnsubscribe } from 'thingies/lib/fanout'; import { PatchBuilder } from '../../../json-crdt-patch/PatchBuilder'; import { MergeFanOut, MicrotaskBufferFanOut } from './fanout'; import { ExtNode } from '../../extensions/ExtNode'; import { ChangeEvent } from './events'; import { type ITimestampStruct } from '../../../json-crdt-patch/clock'; import { type JsonNodeToProxyPathNode } from './proxy'; import type { Extension } from '../../extensions/Extension'; import type { ExtApi } from '../../extensions/types'; import type * as types from './proxy'; import type { Printable } from 'tree-dump/lib/types'; import type { ApiOperation, ApiPath, JsonNodeApi } from './types'; import type { VecNodeExtensionData } from '../../schema/types'; import type { Patch } from '../../../json-crdt-patch'; import type { SyncStore } from '../../../util/events/sync-store'; import type { Model } from '../Model'; import type { JsonNode, JsonNodeView } from '../../nodes'; /** * A generic local changes API for a JSON CRDT node. * * @category Local API */ export declare class NodeApi implements Printable { node: N; readonly api: ModelApi; constructor(node: N, api: ModelApi); /** * Find a child node at the given path starting from this node. * * @param path Path to the child node to find. * @returns JSON CRDT node at the given path. */ find(path?: ApiPath): JsonNode; /** * Find a child node at the given path starting from this node and wrap it in * a local changes API. * * @param path Path to the child node to find. * @returns Local changes API for the child node at the given path. */ in(path?: ApiPath, noThrow?: B): B extends true ? NodeApi | undefined : NodeApi; asVal(noThrow?: B): B extends true ? ValApi | undefined : ValApi; asStr(noThrow?: B): B extends true ? StrApi | undefined : StrApi; asBin(noThrow?: B): B extends true ? BinApi | undefined : BinApi; asArr(noThrow?: B): B extends true ? ArrApi | undefined : ArrApi; asVec(noThrow?: B): B extends true ? VecApi | undefined : VecApi; asObj(noThrow?: B): B extends true ? ObjApi | undefined : ObjApi; asCon(noThrow?: B): B extends true ? ConApi | undefined : ConApi; /** * Returns the API object of the extension if the node is an extension node. * When the `ext` parameter is provided, it checks if the node is an instance * of the given extension and returns the object's TypeScript type. Otherwise, * it returns the API object of the extension, but without any type checking. * * @param ext Extension of the node * @returns API of the extension */ asExt(): JsonNodeApi> | ExtApi | undefined; asExt, EApi extends ExtApi>(ext: Extension): EApi; val(path?: ApiPath, noThrow?: B): B extends true ? ValApi | undefined : ValApi; str(path?: ApiPath, noThrow?: B): B extends true ? StrApi | undefined : StrApi; bin(path?: ApiPath, noThrow?: B): B extends true ? BinApi | undefined : BinApi; arr(path?: ApiPath, noThrow?: B): B extends true ? ArrApi | undefined : ArrApi; vec(path?: ApiPath, noThrow?: B): B extends true ? VecApi | undefined : VecApi; obj(path?: ApiPath, noThrow?: B): B extends true ? ObjApi | undefined : ObjApi; con(path?: ApiPath, noThrow?: B): B extends true ? ConApi | undefined : ConApi; view(): JsonNodeView; select(path?: ApiPath, leaf?: boolean): NodeApi> | undefined; read(path?: ApiPath): unknown; add(path: ApiPath, value: unknown): boolean; replace(path: ApiPath, value: unknown): boolean; remove(path: ApiPath, length?: number): boolean; diff(value: unknown): Patch | undefined; merge(value: unknown): Patch | undefined; merge(path: ApiPath, value: unknown): Patch | undefined; op(operation: ApiOperation): boolean; get s(): types.ProxyNode; get $(): JsonNodeToProxyPathNode; /** * @ignore * @deprecated Use `onChange()` and other `on*()` methods. */ private ev; /** * Event target for listening to node changes. You can subscribe to `"view"` * events, which are triggered every time the node's view changes. * * ```ts * node.events.on('view', () => { * // do something... * }); * ``` * * @ignore * @deprecated Use `onNodeChange()` and other `on*()` methods. */ get events(): NodeEvents; /** * Attaches a listener which executes on every change that is executed * directly on this node. For example, if this is a "str" string node and * you insert or delete text, the listener will be executed. Or if * this is an "obj" object node and keys of this object are changed, this * listener will be executed. * * It does not trigger when child nodes are edit, to include those changes, * use `onSubtreeChange()` or `onChildChange()` methods. * * @see onChildChange() * @see onSubtreeChange() * * @param listener Callback called on every change that is executed directly * on this node. * @returns Returns an unsubscribe function to stop listening to the events. */ onSelfChange(listener: (event: ChangeEvent) => void): FanOutUnsubscribe; /** * Attaches a listener which executes on every change that is applied to this * node's children. Hence, this listener will trigger only for *container* * nodes - nodes that can have child nodes, such as "obj", "arr", "vec", and * "val" nodes. It will not execute on changes made directly to this node. * * If you want to listen to changes on this node as well as its children, use * `onSubtreeChange()` method. If you want to listen to changes on this node * only, use `onSelfChange()` method. * * @see onSelfChange() * @see onSubtreeChange() * * @param listener Callback called on every change that is applied to * children of this node. * @return Returns an unsubscribe function to stop listening to the events. */ onChildChange(listener: (event: ChangeEvent) => void): FanOutUnsubscribe; /** * Attaches a listener which executes on every change that is applied to this * node or any of its child nodes (recursively). This is equivalent to * combining both `onSelfChange()` and `onChildChange()` methods. * * @see onSelfChange() * @see onChildChange() * * @param listener Callback called on every change that is applied to this * node or any of its child nodes. * @return Returns an unsubscribe function to stop listening to the events. */ onSubtreeChange(listener: (event: ChangeEvent) => void): FanOutUnsubscribe; /** * Attaches a listener which executes on every change that is applied to this * node or any of its child nodes (recursively). The `kind` parameter allows * you to specify the type of changes to listen to: `"self"` for changes * directly on this node, `"child"` for changes on child nodes, and `"subtree"` * for both. * * @param kind The type of changes to listen to: `"self"`, `"child"`, or `"subtree"`. * @param listener Callback called on every change that matches the specified type. * @return Returns an unsubscribe function to stop listening to the events. */ onNodeChange(kind: 'self' | 'child' | 'subtree', listener: (event: ChangeEvent) => void): FanOutUnsubscribe; toString(tab?: string): string; } /** * Represents the local changes API for the `con` JSON CRDT node {@link ConNode}. * * @category Local API */ export declare class ConApi = ConNode> extends NodeApi { /** * Returns a proxy object for this node. */ get s(): types.ProxyNodeCon; } /** * Local changes API for the `val` JSON CRDT node {@link ValNode}. * * @category Local API */ export declare class ValApi = ValNode> extends NodeApi { /** * Get API instance of the inner node. * @returns Inner node API. */ get(): JsonNodeApi ? T : JsonNode>; /** * Sets the value of the node. * * @param json JSON/CBOR value or ID (logical timestamp) of the value to set. * @returns Reference to itself. */ set(json: JsonNodeView): void; /** * Returns a proxy object for this node. Allows to access the value of the * node by accessing the `.val` property. */ get s(): types.ProxyNodeVal; } type UnVecNode = N extends VecNode ? T : never; /** * Local changes API for the `vec` JSON CRDT node {@link VecNode}. * * @category Local API */ export declare class VecApi = VecNode> extends NodeApi { /** * Get API instance of a child node. * * @param key Object key to get. * @returns A specified child node API. */ get>(key: K): JsonNodeApi[K]>; /** * Sets a list of elements to the given values. * * @param entries List of index-value pairs to set. * @returns Reference to itself. */ set(entries: [index: number, value: unknown][]): void; push(...values: unknown[]): void; /** * Get the length of the vector without materializing it to a view. * * @returns Length of the vector. */ length(): number; /** * Returns a proxy object for this node. Allows to access vector elements by * index. */ get s(): types.ProxyNodeVec; } type UnObjNode = N extends ObjNode ? T : never; /** * Local changes API for the `obj` JSON CRDT node {@link ObjNode}. * * @category Local API */ export declare class ObjApi = ObjNode> extends NodeApi { /** * Get API instance of a child node. * * @param key Object key to get. * @returns A specified child node API. */ get>(key: K): JsonNodeApi[K]>; /** * Sets a list of keys to the given values. * * @param entries List of key-value pairs to set. * @returns Reference to itself. */ set(entries: Partial>): void; /** * Deletes a list of keys from the object. * * @param keys List of keys to delete. * @returns Reference to itself. */ del(keys: string[]): void; /** * Checks if a key exists in the object. * * @param key Key to check. * @returns True if the key exists, false otherwise. */ has(key: string): boolean; /** Diffs only keys present in `dst` object. */ diffKeys(dst: Record): Patch | undefined; /** Merges only keys present in `dst` object. */ mergeKeys(dst: Record): Patch | undefined; /** * Returns a proxy object for this node. Allows to access object properties * by key. */ get s(): types.ProxyNodeObj; } /** * Local changes API for the `str` JSON CRDT node {@link StrNode}. This API * allows to insert and delete bytes in the UTF-16 string by referencing its * local character positions. * * @category Local API */ export declare class StrApi extends NodeApi { /** * Inserts text at a given position. * * @param index Position at which to insert text. * @param text Text to insert. * @returns Reference to itself. */ ins(index: number, text: string): void; /** * Deletes a range of text at a given position. * * @param index Position at which to delete text. * @param length Number of UTF-16 code units to delete. * @returns Reference to itself. */ del(index: number, length: number): void; /** * Given a character index in local coordinates, find the ID of the character * in the global coordinates. * * @param index Index of the character or `-1` for before the first character. * @returns ID of the character after which the given position is located. */ findId(index: number | -1): ITimestampStruct; /** * Given a position in global coordinates, find the position in local * coordinates. * * @param id ID of the character. * @returns Index of the character in local coordinates. Returns -1 if the * the position refers to the beginning of the string. */ findPos(id: ITimestampStruct): number | -1; /** * Get the length of the string without materializing it to a view. * * @returns Length of the string. */ length(): number; /** * Returns a proxy object for this node. */ get s(): types.ProxyNodeStr; } /** * Local changes API for the `bin` JSON CRDT node {@link BinNode}. This API * allows to insert and delete bytes in the binary string by referencing their * local index. * * @category Local API */ export declare class BinApi extends NodeApi { /** * Inserts octets at a given position. * * @param index Position at which to insert octets. * @param data Octets to insert. * @returns Reference to itself. */ ins(index: number, data: Uint8Array): void; /** * Deletes a range of octets at a given position. * * @param index Position at which to delete octets. * @param length Number of octets to delete. * @returns Reference to itself. */ del(index: number, length: number): void; /** * Get the length of the binary blob without materializing it to a view. * * @returns Length of the binary blob. */ length(): number; /** * Returns a proxy object for this node. */ get s(): types.ProxyNodeBin; } type UnArrNode = N extends ArrNode ? T : never; /** * Local changes API for the `arr` JSON CRDT node {@link ArrNode}. This API * allows to insert and delete elements in the array by referencing their local * index. * * @category Local API */ export declare class ArrApi = ArrNode> extends NodeApi { /** * Get API instance of a child node. * * @param index Index of the element to get. * @returns Child node API for the element at the given index. */ get(index: number): JsonNodeApi>; /** * Inserts elements at a given position. * * @param index Position at which to insert elements. * @param values Values or schema of the elements to insert. */ ins(index: number, values: Array[number]>): void; /** * Inserts elements at the end of the array. * * @param values Values or schema of the elements to insert at the end of the array. */ push(...values: JsonNodeView[number][]): void; /** * Updates (overwrites) an element at a given position. * * @param index Position at which to update the element. * @param value Value or schema of the element to replace with. */ upd(index: number, value: JsonNodeView[number]): void; /** * Deletes a range of elements at a given position. * * @param index Position at which to delete elements. * @param length Number of elements to delete. * @returns Reference to itself. */ del(index: number, length: number): void; /** * Get the length of the array without materializing it to a view. * * @returns Length of the array. */ length(): number; /** * Returns a proxy object that allows to access array elements by index. * * @returns Proxy object that allows to access array elements by index. */ get s(): types.ProxyNodeArr; } /** * Local changes API for a JSON CRDT model. This class is the main entry point * for executing local user actions on a JSON CRDT document. * * @category Local API */ export declare class ModelApi extends ValApi> implements SyncStore> { readonly model: Model; /** * Patch builder for the local changes. */ builder: PatchBuilder; /** * Index of the next operation in builder's patch to be committed locally. * * @ignore */ next: number; /** Emitted before the model is reset, using the `.reset()` method. */ readonly onBeforeReset: FanOut; /** Emitted after the model is reset, using the `.reset()` method. */ readonly onReset: FanOut>>; /** Emitted before a patch is applied using `model.applyPatch()`. */ readonly onBeforePatch: FanOut; /** Emitted after a patch is applied using `model.applyPatch()`. */ readonly onPatch: FanOut; /** Emitted before local changes through `model.api` are applied. */ readonly onBeforeLocalChange: FanOut; /** Emitted after local changes through `model.api` are applied. */ readonly onLocalChange: FanOut; /** Emitted before any change is applied to the model. Combines * `onBeforeReset`, `onBeforePatch` and `onBeforeLocalChange`. */ readonly onBeforeChange: MergeFanOut; /** Emitted when the model changes. Combines `onReset`, `onPatch` and * `onLocalChange`. */ readonly onChange: MergeFanOut; /** * Emitted after local changes through `model.api` are applied. Same as * `.onLocalChange`, but this event buffered withing a microtask. * * @deprecated */ readonly onLocalChanges: MicrotaskBufferFanOut; /** * Emitted when the model changes. Same as `.onChange`, but this event is * emitted once per microtask. */ readonly onChanges: MicrotaskBufferFanOut; /** Emitted before a transaction is started. */ readonly onBeforeTransaction: FanOut; /** Emitted after transaction completes. */ readonly onTransaction: FanOut; /** Emitted when the `model.api` builder change buffer is flushed. */ readonly onFlush: FanOut; /** * @param model Model instance on which the API operates. */ constructor(model: Model); /** * Returns a local change API for the given node. If an instance already * exists, returns the existing instance. */ wrap(node: ValNode): ValApi; wrap(node: StrNode): StrApi; wrap(node: BinNode): BinApi; wrap(node: ArrNode): ArrApi; wrap(node: ObjNode): ObjApi; wrap(node: ConNode): ConApi; wrap(node: VecNode): VecApi; wrap(node: JsonNode): NodeApi; wrap(node: ExtNode): NodeApi; /** * Given a JSON/CBOR value, constructs CRDT nodes recursively out of it and * sets the root node of the model to the constructed nodes. * * @param json JSON/CBOR value to set as the view of the model. * @returns Reference to itself. * * @deprecated Use `.set()` instead. */ root(json: unknown): this; set(json: unknown): this; /** * Apply locally any operations from the `.builder`, which haven't been * applied yet. */ apply(): void; /** * Advance patch pointer to the end without applying the operations. With the * idea that they have already been applied locally. * * You need to manually call `this.onBeforeLocalChange.emit(this.next)` before * calling this method. * * @ignore */ advance(): void; private inTx; transaction(callback: () => void): void; /** * Flushes the builder and returns a patch. * * @returns A JSON CRDT patch. * @todo Make this return undefined if there are no operations in the builder. */ flush(): Patch; stopAutoFlush?: () => void; /** * Begins to automatically flush buffered operations into patches, grouping * operations by microtasks or by transactions. To capture the patch, listen * to the `.onFlush` event. * * @returns Callback to stop auto flushing. */ autoFlush(drainNow?: boolean): () => void; readonly subscribe: (callback: () => void) => FanOutUnsubscribe; readonly getSnapshot: () => JsonNodeView; } export {};