import { type ITimestampStruct } from './clock';
import { type Printable } from 'tree-dump';
import type { PatchBuilder } from './PatchBuilder';
/**
 * @category Patch
 */
export declare class NodeBuilder {
    readonly _build?: ((builder: PatchBuilder) => ITimestampStruct) | undefined;
    constructor(_build?: ((builder: PatchBuilder) => ITimestampStruct) | undefined);
    build(builder: PatchBuilder): ITimestampStruct;
}
/**
 * @category Patch
 */
export declare abstract class SchemaNode extends NodeBuilder implements Printable {
    abstract readonly type: string;
    abstract build(builder: PatchBuilder): ITimestampStruct;
    toString(tab?: string): string;
}
/**
 * This namespace contains all the node builders. Each node builder is a
 * schema for a specific node type. Each node builder has a `build` method
 * that takes a {@link NodeBuilder} and returns the ID of the node.
 */
export declare namespace nodes {
    /**
     * The `con` class represents a "con" JSON CRDT node. As the generic type
     * parameter, it takes the type of the raw value.
     *
     * Example:
     *
     * ```ts
     * s.con(0);
     * s.con('');
     * s.con<number>(123);
     * s.con<0 | 1>(0);
     * ```
     */
    class con<T extends unknown | ITimestampStruct> extends SchemaNode {
        readonly raw: T;
        readonly type = "con";
        constructor(raw: T);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * The `str` class represents a "str" JSON CRDT node. As the generic type
     * parameter, it takes the type of the raw value.
     *
     * Example:
     *
     * ```ts
     * s.str('');
     * s.str('hello');
     * s.str<string>('world');
     * s.str<'' | 'hello' | 'world'>('hello');
     * ```
     */
    class str<T extends string = string> extends SchemaNode {
        readonly raw: T;
        readonly type = "str";
        constructor(raw: T);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * The `bin` class represents a "bin" JSON CRDT node.
     */
    class bin extends SchemaNode {
        readonly raw: Uint8Array;
        readonly type = "bin";
        constructor(raw: Uint8Array);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * The `val` class represents a "val" JSON CRDT node. As the generic type
     * parameter, it takes the type of the inner node builder.
     *
     * Example:
     *
     * ```ts
     * s.val(s.con(0));
     * s.val(s.str(''));
     * s.val(s.str('hello'));
     * ```
     */
    class val<T extends NodeBuilder> extends SchemaNode {
        readonly value: T;
        readonly type = "val";
        constructor(value: T);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * The `vec` class represents a "vec" JSON CRDT node. As the generic type
     * parameter, it takes a tuple of node builders.
     *
     * Example:
     *
     * ```ts
     * s.vec(s.con(0), s.con(1));
     * s.vec(s.str(''), s.str('hello'));
     * ```
     */
    class vec<T extends (NodeBuilder | undefined)[]> extends SchemaNode {
        readonly value: T;
        readonly type = "vec";
        constructor(value: T);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * The `obj` class represents a "obj" JSON CRDT node. As the generic type
     * parameter, it takes a record of node builders. The optional generic type
     * parameter is a record of optional keys.
     *
     * Example:
     *
     * ```ts
     * s.obj({
     *   name: s.str(''),
     *   age: s.con(0),
     * });
     * ```
     *
     * Specify optional keys as the second argument:
     *
     * ```ts
     * s.obj(
     *   {
     *     href: s.str('https://example.com'),
     *   },
     *   {
     *     title: s.str(''),
     *   },
     * )
     * ```
     *
     * Or, specify only the type, using the `optional` method:
     *
     * ```ts
     * s.obj({
     *   href: s.str('https://example.com'),
     * })
     *   .optional<nodes.obj({
     *     title: nodes.str,
     *   })>()
     * ```
     */
    class obj<T extends Record<string, NodeBuilder>, O extends Record<string, NodeBuilder> = {}> extends SchemaNode {
        readonly obj: T;
        readonly opt?: O | undefined;
        readonly type = "obj";
        constructor(obj: T, opt?: O | undefined);
        optional<OO extends Record<string, NodeBuilder>>(): obj<T, O & OO>;
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * A type alias for {@link obj}. It creates a "map" node schema, which is an
     * object where a key can be any string and the value is of the same type.
     *
     * Example:
     *
     * ```ts
     * s.map<nodes.con<number>>
     * ```
     */
    type map<R extends NodeBuilder> = obj<Record<string, R>, Record<string, R>>;
    /**
     * The `arr` class represents a "arr" JSON CRDT node. As the generic type
     * parameter, it an array of node builders.
     *
     * Example:
     *
     * ```ts
     * s.arr([s.con(0), s.con(1)]);
     * s.arr([s.str(''), s.str('hello')]);
     * ```
     */
    class arr<T extends NodeBuilder> extends SchemaNode {
        readonly arr: T[];
        readonly type = "arr";
        constructor(arr: T[]);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * Creates an extension node schema. The extension node is a tuple with a
     * sentinel header and a data node. The sentinel header is a 3-byte
     * {@link Uint8Array}, which makes this "vec" node to be treated as an
     * extension "ext" node.
     *
     * The 3-byte header consists of the extension ID, the SID of the tuple ID,
     * and the time of the tuple ID:
     *
     * - 1 byte for the extension id
     * - 1 byte for the sid of the tuple id, modulo 256
     * - 1 byte for the time of the tuple id, modulo 256
     */
    class ext<ID extends number, T extends NodeBuilder> extends SchemaNode {
        readonly id: ID;
        readonly data: T;
        readonly type = "ext";
        /**
         * @param id A unique extension ID.
         * @param data Schema of the data node of the extension.
         */
        constructor(id: ID, data: T);
        build(builder: PatchBuilder): ITimestampStruct;
        toString(tab?: string): string;
    }
    /**
     * Converts a POJO value to a JSON CRDT node schema. It recursively converts
     * the value to a node schema, where each property is a node builder.
     */
    type json<V> = V extends NodeBuilder ? V : V extends Array<infer T> ? nodes.arr<json<T>> : V extends Uint8Array ? nodes.bin : V extends Record<string, any> ? nodes.obj<{
        [K in keyof V]: jsonCon<V[K]>;
    }> : V extends string ? nodes.str<V> : V extends boolean ? nodes.val<nodes.con<boolean>> : nodes.val<nodes.con<V>>;
    /**
     * Same as {@link json}, but converts constant values to
     * {@link nodes.con} nodes, instead wrapping them into {@link nodes.val} nodes.
     */
    type jsonCon<V> = V extends number ? nodes.con<V> : V extends boolean ? nodes.con<V> : V extends null ? nodes.con<V> : V extends undefined ? nodes.con<V> : V extends ITimestampStruct ? nodes.val<nodes.con<V>> : json<V>;
}
/**
 * Schema builder. Use this to create a JSON CRDT model schema and the default
 * value.
 *
 * Example:
 *
 * ```typescript
 * const schema = s.obj({
 *   name: s.str(''),
 *   age: s.con(0),
 *   tags: s.arr<nodes.con<string>>([]),
 * });
 * ```
 */
export declare const schema: {
    /**
     * Creates a "con" node schema and the default value.
     *
     * @param raw Raw default value.
     */
    con: <T extends unknown | ITimestampStruct>(raw: T) => nodes.con<T>;
    /**
     * Creates a "str" node schema and the default value.
     *
     * @param str Default value.
     */
    str: <T extends string>(str: T) => nodes.str<T>;
    /**
     * Creates a "bin" node schema and the default value.
     *
     * @param bin Default value.
     */
    bin: (bin: Uint8Array) => nodes.bin;
    /**
     * Creates a "val" node schema and the default value.
     *
     * @param val Default value.
     */
    val: <T extends NodeBuilder>(val: T) => nodes.val<T>;
    /**
     * Creates a "vec" node schema and the default value.
     *
     * @param vec Default value.
     */
    vec: <T extends NodeBuilder[]>(...vec: T) => nodes.vec<T>;
    /**
     * Creates a "obj" node schema and the default value.
     *
     * @param obj Default value, required object keys.
     * @param opt Default value of optional object keys.
     */
    obj: <T extends Record<string, NodeBuilder>, O extends Record<string, NodeBuilder>>(obj: T, opt?: O) => nodes.obj<T, O>;
    /**
     * This is an alias for {@link schema.obj}. It creates a "map" node schema,
     * which is an object where a key can be any string and the value is of the
     * same type.
     *
     * @param obj Default value.
     */
    map: <R extends NodeBuilder>(obj: Record<string, R>) => nodes.map<R>;
    /**
     * Creates an "arr" node schema and the default value.
     *
     * @param arr Default value.
     */
    arr: <T extends NodeBuilder>(arr: T[]) => nodes.arr<T>;
    /**
     * Recursively creates a node tree from any POJO.
     */
    json: <T>(value: T) => nodes.json<T>;
    /**
     * Recursively creates a schema node tree from any POJO. Same as {@link json}, but
     * converts constant values to {@link nodes.con} nodes, instead wrapping them into
     * {@link nodes.val} nodes.
     *
     * @todo Remove this once "arr" RGA supports in-place updates.
     */
    jsonCon: <T>(value: T) => nodes.jsonCon<T>;
    /**
     * Creates an extension node schema.
     *
     * @param id A unique extension ID.
     * @param data Schema of the data node of the extension.
     */
    ext: <ID extends number, T extends NodeBuilder>(id: ID, data: T) => nodes.ext<ID, T>;
};
/**
 * Schema builder. Use this to create a JSON CRDT model schema and the default
 * value. Alias for {@link schema}.
 */
export declare const s: {
    /**
     * Creates a "con" node schema and the default value.
     *
     * @param raw Raw default value.
     */
    con: <T extends unknown | ITimestampStruct>(raw: T) => nodes.con<T>;
    /**
     * Creates a "str" node schema and the default value.
     *
     * @param str Default value.
     */
    str: <T extends string>(str: T) => nodes.str<T>;
    /**
     * Creates a "bin" node schema and the default value.
     *
     * @param bin Default value.
     */
    bin: (bin: Uint8Array) => nodes.bin;
    /**
     * Creates a "val" node schema and the default value.
     *
     * @param val Default value.
     */
    val: <T extends NodeBuilder>(val: T) => nodes.val<T>;
    /**
     * Creates a "vec" node schema and the default value.
     *
     * @param vec Default value.
     */
    vec: <T extends NodeBuilder[]>(...vec: T) => nodes.vec<T>;
    /**
     * Creates a "obj" node schema and the default value.
     *
     * @param obj Default value, required object keys.
     * @param opt Default value of optional object keys.
     */
    obj: <T extends Record<string, NodeBuilder>, O extends Record<string, NodeBuilder>>(obj: T, opt?: O) => nodes.obj<T, O>;
    /**
     * This is an alias for {@link schema.obj}. It creates a "map" node schema,
     * which is an object where a key can be any string and the value is of the
     * same type.
     *
     * @param obj Default value.
     */
    map: <R extends NodeBuilder>(obj: Record<string, R>) => nodes.map<R>;
    /**
     * Creates an "arr" node schema and the default value.
     *
     * @param arr Default value.
     */
    arr: <T extends NodeBuilder>(arr: T[]) => nodes.arr<T>;
    /**
     * Recursively creates a node tree from any POJO.
     */
    json: <T>(value: T) => nodes.json<T>;
    /**
     * Recursively creates a schema node tree from any POJO. Same as {@link json}, but
     * converts constant values to {@link nodes.con} nodes, instead wrapping them into
     * {@link nodes.val} nodes.
     *
     * @todo Remove this once "arr" RGA supports in-place updates.
     */
    jsonCon: <T>(value: T) => nodes.jsonCon<T>;
    /**
     * Creates an extension node schema.
     *
     * @param id A unique extension ID.
     * @param data Schema of the data node of the extension.
     */
    ext: <ID extends number, T extends NodeBuilder>(id: ID, data: T) => nodes.ext<ID, T>;
};
