UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

458 lines (457 loc) 16 kB
import { type ITimestampStruct } from '../../../json-crdt-patch/clock'; import { ObjNode, ArrNode, BinNode, ConNode, VecNode, ValNode, StrNode, RootNode } from '../../nodes'; import { NodeEvents } from './NodeEvents'; import { FanOut } from 'thingies/lib/fanout'; import { PatchBuilder } from '../../../json-crdt-patch/PatchBuilder'; import { MergeFanOut, MicrotaskBufferFanOut } from './fanout'; import { ExtNode } from '../../extensions/ExtNode'; 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 JsonNodeToProxyPathNode } from './proxy'; 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<N extends JsonNode = JsonNode> implements Printable { node: N; readonly api: ModelApi<any>; constructor(node: N, api: ModelApi<any>); /** @ignore */ 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... * }); * ``` */ get events(): NodeEvents<N>; /** * 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): ValApi<ValNode<any>>; asVal(): ValApi; asStr(): StrApi; asBin(): BinApi; asArr(): ArrApi; asVec(): VecApi; asObj(): ObjApi; asCon(): 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<VecNodeExtensionData<N>> | ExtApi<any> | undefined; asExt<EN extends ExtNode<any, any>, EApi extends ExtApi<EN>>(ext: Extension<any, any, EN, EApi, any, any>): EApi; val(path?: ApiPath): ValApi; str(path?: ApiPath): StrApi; bin(path?: ApiPath): BinApi; arr(path?: ApiPath): ArrApi; vec(path?: ApiPath): VecApi; obj(path?: ApiPath): ObjApi; con(path?: ApiPath): ConApi; view(): JsonNodeView<N>; select(path?: ApiPath, leaf?: boolean): NodeApi<JsonNode<unknown>> | 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; op(operation: ApiOperation): boolean; get s(): types.ProxyNode<N>; get $(): JsonNodeToProxyPathNode<N>; toString(tab?: string): string; } /** * Represents the local changes API for the `con` JSON CRDT node {@link ConNode}. * * @category Local API */ export declare class ConApi<N extends ConNode<any> = ConNode<any>> extends NodeApi<N> { /** * Returns a proxy object for this node. */ get s(): types.ProxyNodeCon<N>; } /** * Local changes API for the `val` JSON CRDT node {@link ValNode}. * * @category Local API */ export declare class ValApi<N extends ValNode<any> = ValNode<any>> extends NodeApi<N> { /** * Get API instance of the inner node. * @returns Inner node API. */ get(): JsonNodeApi<N extends ValNode<infer T> ? 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<N>): 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<N>; } type UnVecNode<N> = N extends VecNode<infer T> ? T : never; /** * Local changes API for the `vec` JSON CRDT node {@link VecNode}. * * @category Local API */ export declare class VecApi<N extends VecNode<any> = VecNode<any>> extends NodeApi<N> { /** * Get API instance of a child node. * * @param key Object key to get. * @returns A specified child node API. */ get<K extends keyof UnVecNode<N>>(key: K): JsonNodeApi<UnVecNode<N>[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<N>; } type UnObjNode<N> = N extends ObjNode<infer T> ? T : never; /** * Local changes API for the `obj` JSON CRDT node {@link ObjNode}. * * @category Local API */ export declare class ObjApi<N extends ObjNode<any> = ObjNode<any>> extends NodeApi<N> { /** * Get API instance of a child node. * * @param key Object key to get. * @returns A specified child node API. */ get<K extends keyof UnObjNode<N>>(key: K): JsonNodeApi<UnObjNode<N>[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<JsonNodeView<N>>): 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; /** * Returns a proxy object for this node. Allows to access object properties * by key. */ get s(): types.ProxyNodeObj<N>; } /** * 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<StrNode> { /** * 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<BinNode> { /** * 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> = N extends ArrNode<infer T> ? 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<N extends ArrNode<any> = ArrNode<any>> extends NodeApi<N> { /** * 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<UnArrNode<N>>; /** * 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<JsonNodeView<N>[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<N>[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<N>[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<N>; } /** * 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<N extends JsonNode = JsonNode> extends ValApi<RootNode<N>> implements SyncStore<JsonNodeView<N>> { readonly model: Model<N>; /** * 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<void>; /** Emitted after the model is reset, using the `.reset()` method. */ readonly onReset: FanOut<void>; /** Emitted before a patch is applied using `model.applyPatch()`. */ readonly onBeforePatch: FanOut<Patch>; /** Emitted after a patch is applied using `model.applyPatch()`. */ readonly onPatch: FanOut<Patch>; /** Emitted before local changes through `model.api` are applied. */ readonly onBeforeLocalChange: FanOut<number>; /** Emitted after local changes through `model.api` are applied. */ readonly onLocalChange: FanOut<number>; /** * Emitted after local changes through `model.api` are applied. Same as * `.onLocalChange`, but this event buffered withing a microtask. */ readonly onLocalChanges: MicrotaskBufferFanOut<number>; /** Emitted before a transaction is started. */ readonly onBeforeTransaction: FanOut<void>; /** Emitted after transaction completes. */ readonly onTransaction: FanOut<void>; /** Emitted when the model changes. Combines `onReset`, `onPatch` and `onLocalChange`. */ readonly onChange: MergeFanOut<number | Patch | undefined>; /** Emitted when the model changes. Same as `.onChange`, but this event is emitted once per microtask. */ readonly onChanges: MicrotaskBufferFanOut<number | Patch | undefined>; /** Emitted when the `model.api` builder change buffer is flushed. */ readonly onFlush: FanOut<Patch>; /** * @param model Model instance on which the API operates. */ constructor(model: Model<N>); /** * 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<any>): 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<any, any>): 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) => import("thingies/lib/fanout").FanOutUnsubscribe; readonly getSnapshot: () => JsonNodeView<N>; } export {};