import { JSONSchema7 } from 'json-schema';

/**
 * Throws an error if multiple copies of a Liveblocks package are being loaded
 * at runtime. This likely indicates a packaging issue with the project.
 */
declare function detectDupes(pkgName: string, pkgVersion: string | false, // false if not built yet
pkgFormat: string | false): void;

/**
 * This helper type is effectively a no-op, but will force TypeScript to
 * "evaluate" any named helper types in its definition. This can sometimes make
 * API signatures clearer in IDEs.
 *
 * For example, in:
 *
 *   type Payload<T> = { data: T };
 *
 *   let r1: Payload<string>;
 *   let r2: Resolve<Payload<string>>;
 *
 * The inferred type of `r1` is going to be `Payload<string>` which shows up in
 * editor hints, and it may be unclear what's inside if you don't know the
 * definition of `Payload`.
 *
 * The inferred type of `r2` is going to be `{ data: string }`, which may be
 * more helpful.
 *
 * This trick comes from:
 * https://effectivetypescript.com/2022/02/25/gentips-4-display/
 */
type Resolve<T> = T extends (...args: unknown[]) => unknown ? T : {
    [K in keyof T]: T[K];
};

/**
 * Relaxes a discriminated union type definition, by explicitly adding
 * properties defined in any other member as 'never'.
 *
 * This makes accessing the members much more relaxed in TypeScript.
 *
 * For example:
 *   type MyUnion = Relax<
 *     | { foo: string }
 *     | { foo: number; bar: string; }
 *     | { qux: boolean }
 *   >;
 *
 *   // With Relax, accessing is much easier:
 *   union.foo;       // string | number | undefined
 *   union.bar;       // string | undefined
 *   union.qux;       // boolean
 *   union.whatever;  // Error: Property 'whatever' does not exist on type 'MyUnion'
 *
 *   // Without Relax, these would all be type errors:
 *   union.foo; // Error: Property 'foo' does not exist on type 'MyUnion'
 *   union.bar; // Error: Property 'bar' does not exist on type 'MyUnion'
 *   union.qux; // Error: Property 'qux' does not exist on type 'MyUnion'
 */
type Relax<T> = DistributiveRelax<T, T extends any ? keyof T : never>;
type DistributiveRelax<T, Ks extends string | number | symbol> = T extends any ? Resolve<{
    [K in keyof T]: T[K];
} & {
    [K in Exclude<Ks, keyof T>]?: never;
}> : never;

type CustomAuthenticationResult = Relax<{
    token: string;
} | {
    error: "forbidden";
    reason: string;
} | {
    error: string;
    reason: string;
}>;

/**
 * Represents an indefinitely deep arbitrary JSON data structure. There are
 * four types that make up the Json family:
 *
 * - Json         any legal JSON value
 * - JsonScalar   any legal JSON leaf value (no lists or objects)
 * - JsonArray    a JSON value whose outer type is an array
 * - JsonObject   a JSON value whose outer type is an object
 *
 */
type Json = JsonScalar | JsonArray | JsonObject;
type JsonScalar = string | number | boolean | null;
type JsonArray = Json[];
/**
 * Any valid JSON object.
 */
type JsonObject = {
    [key: string]: Json | undefined;
};
declare function isJsonScalar(data: Json): data is JsonScalar;
declare function isJsonArray(data: Json): data is JsonArray;
declare function isJsonObject(data: Json): data is JsonObject;

/**
 * Represents some constraints for user info. Basically read this as: "any JSON
 * object is fine, but _if_ it has a name field, it _must_ be a string."
 * (Ditto for avatar.)
 */
type IUserInfo = {
    [key: string]: Json | undefined;
    name?: string;
    avatar?: string;
};
/**
 * This type is used by clients to define the metadata for a user.
 */
type BaseUserMeta = {
    /**
     * The id of the user that has been set in the authentication endpoint.
     * Useful to get additional information about the connected user.
     */
    id?: string;
    /**
     * Additional user information that has been set in the authentication endpoint.
     */
    info?: IUserInfo;
};

declare enum Permission {
    Read = "room:read",
    Write = "room:write",
    PresenceWrite = "room:presence:write",
    CommentsWrite = "comments:write",
    CommentsRead = "comments:read"
}

type RenameDataField<T, TFieldName extends string> = T extends any ? {
    [K in keyof T as K extends "data" ? TFieldName : K]: T[K];
} : never;
type AsyncLoading<F extends string = "data"> = RenameDataField<{
    readonly isLoading: true;
    readonly data?: never;
    readonly error?: never;
}, F>;
type AsyncSuccess<T, F extends string = "data"> = RenameDataField<{
    readonly isLoading: false;
    readonly data: T;
    readonly error?: never;
}, F>;
type AsyncError<F extends string = "data"> = RenameDataField<{
    readonly isLoading: false;
    readonly data?: never;
    readonly error: Error;
}, F>;
type AsyncResult<T, F extends string = "data"> = AsyncLoading<F> | AsyncSuccess<T, F> | AsyncError<F>;

type Callback<T> = (event: T) => void;
type UnsubscribeCallback = () => void;
type Observable<T> = {
    /**
     * Register a callback function to be called whenever the event source emits
     * an event.
     */
    subscribe(callback: Callback<T>): UnsubscribeCallback;
    /**
     * Register a one-time callback function to be called whenever the event
     * source emits an event. After the event fires, the callback is
     * auto-unsubscribed.
     */
    subscribeOnce(callback: Callback<T>): UnsubscribeCallback;
    /**
     * Returns a promise that will resolve when an event is emitted by this
     * event source. Optionally, specify a predicate that has to match. The first
     * event matching that predicate will then resolve the promise.
     */
    waitUntil(predicate?: (event: T) => boolean): Promise<T>;
};
type EventSource<T> = Observable<T> & {
    /**
     * Notify all subscribers about the event. Will return `false` if there
     * weren't any subscribers at the time the .notify() was called, or `true` if
     * there was at least one subscriber.
     */
    notify(event: T): boolean;
    /**
     * Returns the number of active subscribers.
     */
    count(): number;
    /**
     * Observable instance, which can be used to subscribe to this event source
     * in a readonly fashion. Safe to publicly expose.
     */
    observable: Observable<T>;
    /**
     * Disposes of this event source.
     *
     * Will clears all registered event listeners. None of the registered
     * functions will ever get called again.
     *
     * WARNING!
     * Be careful when using this API, because the subscribers may not have any
     * idea they won't be notified anymore.
     */
    dispose(): void;
};
/**
 * makeEventSource allows you to generate a subscribe/notify pair of functions
 * to make subscribing easy and to get notified about events.
 *
 * The events are anonymous, so you can use it to define events, like so:
 *
 *   const event1 = makeEventSource();
 *   const event2 = makeEventSource();
 *
 *   event1.subscribe(foo);
 *   event1.subscribe(bar);
 *   event2.subscribe(qux);
 *
 *   // Unsubscription is pretty standard
 *   const unsub = event2.subscribe(foo);
 *   unsub();
 *
 *   event1.notify();  // Now foo and bar will get called
 *   event2.notify();  // Now qux will get called (but foo will not, since it's unsubscribed)
 *
 */
declare function makeEventSource<T>(): EventSource<T>;

type BatchStore<O, I> = {
    subscribe: (callback: Callback<void>) => UnsubscribeCallback;
    enqueue: (input: I) => Promise<void>;
    getItemState: (input: I) => AsyncResult<O> | undefined;
    invalidate: (inputs?: I[]) => void;
};

declare const kTrigger: unique symbol;
/**
 * Runs a callback function that is allowed to change multiple signals. At the
 * end of the batch, all changed signals will be notified (at most once).
 *
 * Nesting batches is supported.
 */
declare function batch(callback: Callback<void>): void;
type SignalType<S extends ISignal<any>> = S extends ISignal<infer T> ? T : never;
interface ISignal<T> {
    get(): T;
    subscribe(callback: Callback<void>): UnsubscribeCallback;
    addSink(sink: DerivedSignal<unknown>): void;
    removeSink(sink: DerivedSignal<unknown>): void;
}
/**
 * Base functionality every Signal implementation needs.
 */
declare abstract class AbstractSignal<T> implements ISignal<T>, Observable<void> {
    #private;
    constructor(equals?: (a: T, b: T) => boolean);
    dispose(): void;
    abstract get(): T;
    get hasWatchers(): boolean;
    [kTrigger](): void;
    subscribe(callback: Callback<void>): UnsubscribeCallback;
    subscribeOnce(callback: Callback<void>): UnsubscribeCallback;
    waitUntil(): never;
    markSinksDirty(): void;
    addSink(sink: DerivedSignal<unknown>): void;
    removeSink(sink: DerivedSignal<unknown>): void;
    asReadonly(): ISignal<T>;
}
declare class Signal<T> extends AbstractSignal<T> {
    #private;
    constructor(value: T, equals?: (a: T, b: T) => boolean);
    dispose(): void;
    get(): T;
    set(newValue: T | ((oldValue: T) => T)): void;
}
declare class DerivedSignal<T> extends AbstractSignal<T> {
    #private;
    static from<Ts extends unknown[], V>(...args: [...signals: {
        [K in keyof Ts]: ISignal<Ts[K]>;
    }, transform: (...values: Ts) => V]): DerivedSignal<V>;
    static from<Ts extends unknown[], V>(...args: [...signals: {
        [K in keyof Ts]: ISignal<Ts[K]>;
    }, transform: (...values: Ts) => V, equals: (a: V, b: V) => boolean]): DerivedSignal<V>;
    private constructor();
    dispose(): void;
    get isDirty(): boolean;
    markDirty(): void;
    get(): T;
    /**
     * Called by the Signal system if one or more of the dependent signals have
     * changed. In the case of a DerivedSignal, we'll only want to re-evaluate
     * the actual value if it's being watched, or any of their sinks are being
     * watched actively.
     */
    [kTrigger](): void;
}
/**
 * A MutableSignal is a bit like Signal, except its state is managed by
 * a single value whose reference does not change but is mutated.
 *
 * Similar to how useSyncExternalState() works in React, there is a way to read
 * the current state at any point in time synchronously, and a way to update
 * its reference.
 */
declare class MutableSignal<T extends object> extends AbstractSignal<T> {
    #private;
    constructor(initialState: T);
    dispose(): void;
    get(): T;
    /**
     * Invokes a callback function that is allowed to mutate the given state
     * value. Do not change the value outside of the callback.
     *
     * If the callback explicitly returns `false`, it's assumed that the state
     * was not changed.
     */
    mutate(callback?: (state: T) => void | boolean): void;
}

type ContextualPromptResponse = Relax<{
    type: "insert";
    text: string;
} | {
    type: "replace";
    text: string;
} | {
    type: "other";
    text: string;
}>;
type ContextualPromptContext = {
    beforeSelection: string;
    selection: string;
    afterSelection: string;
};

declare enum OpCode {
    INIT = 0,
    SET_PARENT_KEY = 1,
    CREATE_LIST = 2,
    UPDATE_OBJECT = 3,
    CREATE_OBJECT = 4,
    DELETE_CRDT = 5,
    DELETE_OBJECT_KEY = 6,
    CREATE_MAP = 7,
    CREATE_REGISTER = 8
}
/**
 * These operations are the payload for {@link UpdateStorageServerMsg} messages
 * only.
 */
type Op = AckOp | CreateOp | UpdateObjectOp | DeleteCrdtOp | SetParentKeyOp | DeleteObjectKeyOp;
type CreateOp = CreateObjectOp | CreateRegisterOp | CreateMapOp | CreateListOp;
type UpdateObjectOp = {
    readonly opId?: string;
    readonly id: string;
    readonly type: OpCode.UPDATE_OBJECT;
    readonly data: Partial<JsonObject>;
};
type CreateObjectOp = {
    readonly opId?: string;
    readonly id: string;
    readonly intent?: "set";
    readonly deletedId?: string;
    readonly type: OpCode.CREATE_OBJECT;
    readonly parentId: string;
    readonly parentKey: string;
    readonly data: JsonObject;
};
type CreateListOp = {
    readonly opId?: string;
    readonly id: string;
    readonly intent?: "set";
    readonly deletedId?: string;
    readonly type: OpCode.CREATE_LIST;
    readonly parentId: string;
    readonly parentKey: string;
};
type CreateMapOp = {
    readonly opId?: string;
    readonly id: string;
    readonly intent?: "set";
    readonly deletedId?: string;
    readonly type: OpCode.CREATE_MAP;
    readonly parentId: string;
    readonly parentKey: string;
};
type CreateRegisterOp = {
    readonly opId?: string;
    readonly id: string;
    readonly intent?: "set";
    readonly deletedId?: string;
    readonly type: OpCode.CREATE_REGISTER;
    readonly parentId: string;
    readonly parentKey: string;
    readonly data: Json;
};
type DeleteCrdtOp = {
    readonly opId?: string;
    readonly id: string;
    readonly type: OpCode.DELETE_CRDT;
};
type AckOp = {
    readonly type: OpCode.DELETE_CRDT;
    readonly id: "ACK";
    readonly opId: string;
};
/**
 * Create an Op that can be used as an acknowledgement for the given opId, to
 * send back to the originating client in cases where the server decided to
 * ignore the Op and not forward it.
 *
 * Why?
 * It's important for the client to receive an acknowledgement for this, so
 * that it can correctly update its own unacknowledged Ops administration.
 * Otherwise it could get in "synchronizing" state indefinitely.
 *
 * CLEVER HACK
 * Introducing a new Op type for this would not be backward-compatible as
 * receiving such Op would crash old clients :(
 * So the clever backward-compatible hack pulled here is that we codify the
 * acknowledgement as a "deletion Op" for the non-existing node id "ACK". In
 * old clients such Op is accepted, but will effectively be a no-op as that
 * node does not exist, but as a side-effect the Op will get acknowledged.
 */
declare function ackOp(opId: string): AckOp;
type SetParentKeyOp = {
    readonly opId?: string;
    readonly id: string;
    readonly type: OpCode.SET_PARENT_KEY;
    readonly parentKey: string;
};
type DeleteObjectKeyOp = {
    readonly opId?: string;
    readonly id: string;
    readonly type: OpCode.DELETE_OBJECT_KEY;
    readonly key: string;
};

declare enum ClientMsgCode {
    UPDATE_PRESENCE = 100,
    BROADCAST_EVENT = 103,
    FETCH_STORAGE = 200,
    UPDATE_STORAGE = 201,
    FETCH_YDOC = 300,
    UPDATE_YDOC = 301
}
/**
 * Messages that can be sent from the client to the server.
 */
type ClientMsg<P extends JsonObject, E extends Json> = BroadcastEventClientMsg<E> | UpdatePresenceClientMsg<P> | UpdateStorageClientMsg | FetchStorageClientMsg | FetchYDocClientMsg | UpdateYDocClientMsg;
type BroadcastEventClientMsg<E extends Json> = {
    type: ClientMsgCode.BROADCAST_EVENT;
    event: E;
};
type UpdatePresenceClientMsg<P extends JsonObject> = {
    readonly type: ClientMsgCode.UPDATE_PRESENCE;
    /**
     * Set this to any number to signify that this is a Full Presence™
     * update, not a patch.
     *
     * The numeric value itself no longer has specific meaning. Historically,
     * this field was intended so that clients could ignore these broadcasted
     * full presence messages, but it turned out that getting a full presence
     * "keyframe" from time to time was useful.
     *
     * So nowadays, the presence (pun intended) of this `targetActor` field
     * is a backward-compatible way of expressing that the `data` contains
     * all presence fields, and isn't a partial "patch".
     */
    readonly targetActor: number;
    readonly data: P;
} | {
    readonly type: ClientMsgCode.UPDATE_PRESENCE;
    /**
     * Absence of the `targetActor` field signifies that this is a Partial
     * Presence™ "patch".
     */
    readonly targetActor?: undefined;
    readonly data: Partial<P>;
};
type UpdateStorageClientMsg = {
    readonly type: ClientMsgCode.UPDATE_STORAGE;
    readonly ops: Op[];
};
type FetchStorageClientMsg = {
    readonly type: ClientMsgCode.FETCH_STORAGE;
};
type FetchYDocClientMsg = {
    readonly type: ClientMsgCode.FETCH_YDOC;
    readonly vector: string;
    readonly guid?: string;
    readonly v2?: boolean;
};
type UpdateYDocClientMsg = {
    readonly type: ClientMsgCode.UPDATE_YDOC;
    readonly update: string;
    readonly guid?: string;
    readonly v2?: boolean;
};

/**
 * Represents an indefinitely deep arbitrary immutable data
 * structure, as returned by the .toImmutable().
 */
type Immutable = Scalar | ImmutableList | ImmutableObject | ImmutableMap;
type Scalar = string | number | boolean | null;
type ImmutableList = readonly Immutable[];
type ImmutableObject = {
    readonly [key: string]: Immutable | undefined;
};
type ImmutableMap = ReadonlyMap<string, Immutable>;

type UpdateDelta = {
    type: "update";
} | {
    type: "delete";
};

/**
 * "Plain LSON" is a JSON-based format that's used when serializing Live structures
 * to send them over HTTP (e.g. in the API endpoint to let users upload their initial
 * Room storage, in the API endpoint to fetch a Room's storage, ...).
 *
 * In the client, you would typically create LSON values using:
 *
 *    new LiveObject({ x: 0, y: 0 })
 *
 * But over HTTP, this has to be serialized somehow. The "Plain LSON" format
 * is what's used in the POST /init-storage-new endpoint, to allow users to
 * control which parts of their data structure should be considered "Live"
 * objects, and which parts are "normal" objects.
 *
 * So if they have a structure like:
 *
 *    { x: 0, y: 0 }
 *
 * And want to make it a Live object, they can serialize it by wrapping it in
 * a special "annotation":
 *
 *    {
 *      "liveblocksType": "LiveObject",
 *      "data": { x: 0, y: 0 },
 *    }
 *
 * This "Plain LSON" data format defines exactly those wrappings.
 *
 * To summarize:
 *
 *   LSON value            |  Plain LSON equivalent
 *   ----------------------+----------------------------------------------
 *   42                    |  42
 *   [1, 2, 3]             |  [1, 2, 3]
 *   { x: 0, y: 0 }        |  { x: 0, y: 0 }
 *   ----------------------+----------------------------------------------
 *   new LiveList(...)     |  { liveblocksType: "LiveList",   data: ... }
 *   new LiveMap(...)      |  { liveblocksType: "LiveMap",    data: ... }
 *   new LiveObject(...)   |  { liveblocksType: "LiveObject", data: ... }
 *
 */

type PlainLsonFields = Record<string, PlainLson>;
type PlainLsonObject = {
    liveblocksType: "LiveObject";
    data: PlainLsonFields;
};
type PlainLsonMap = {
    liveblocksType: "LiveMap";
    data: PlainLsonFields;
};
type PlainLsonList = {
    liveblocksType: "LiveList";
    data: PlainLson[];
};
type PlainLson = PlainLsonObject | PlainLsonMap | PlainLsonList | Json;

type IdTuple<T> = [id: string, value: T];
declare enum CrdtType {
    OBJECT = 0,
    LIST = 1,
    MAP = 2,
    REGISTER = 3
}
type SerializedCrdt = SerializedRootObject | SerializedChild;
type SerializedChild = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
type SerializedRootObject = {
    readonly type: CrdtType.OBJECT;
    readonly data: JsonObject;
    readonly parentId?: never;
    readonly parentKey?: never;
};
type SerializedObject = {
    readonly type: CrdtType.OBJECT;
    readonly parentId: string;
    readonly parentKey: string;
    readonly data: JsonObject;
};
type SerializedList = {
    readonly type: CrdtType.LIST;
    readonly parentId: string;
    readonly parentKey: string;
};
type SerializedMap = {
    readonly type: CrdtType.MAP;
    readonly parentId: string;
    readonly parentKey: string;
};
type SerializedRegister = {
    readonly type: CrdtType.REGISTER;
    readonly parentId: string;
    readonly parentKey: string;
    readonly data: Json;
};
declare function isRootCrdt(crdt: SerializedCrdt): crdt is SerializedRootObject;
declare function isChildCrdt(crdt: SerializedCrdt): crdt is SerializedChild;

type LiveObjectUpdateDelta<O extends {
    [key: string]: unknown;
}> = {
    [K in keyof O]?: UpdateDelta | undefined;
};
/**
 * A LiveObject notification that is sent in-client to any subscribers whenever
 * one or more of the entries inside the LiveObject instance have changed.
 */
type LiveObjectUpdates<TData extends LsonObject> = {
    type: "LiveObject";
    node: LiveObject<TData>;
    updates: LiveObjectUpdateDelta<TData>;
};
/**
 * The LiveObject class is similar to a JavaScript object that is synchronized on all clients.
 * Keys should be a string, and values should be serializable to JSON.
 * If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
 */
declare class LiveObject<O extends LsonObject> extends AbstractCrdt {
    #private;
    /** @private Do not use this API directly */
    static _fromItems<O extends LsonObject>(items: IdTuple<SerializedCrdt>[], pool: ManagedPool): LiveObject<O>;
    constructor(obj?: O);
    /**
     * Transform the LiveObject into a javascript object
     */
    toObject(): O;
    /**
     * Adds or updates a property with a specified key and a value.
     * @param key The key of the property to add
     * @param value The value of the property to add
     */
    set<TKey extends keyof O>(key: TKey, value: O[TKey]): void;
    /**
     * Returns a specified property from the LiveObject.
     * @param key The key of the property to get
     */
    get<TKey extends keyof O>(key: TKey): O[TKey];
    /**
     * Deletes a key from the LiveObject
     * @param key The key of the property to delete
     */
    delete(key: keyof O): void;
    /**
     * Adds or updates multiple properties at once with an object.
     * @param patch The object used to overrides properties
     */
    update(patch: Partial<O>): void;
    toImmutable(): ToImmutable<O>;
    clone(): LiveObject<O>;
}

/**
 * Helper type to convert any valid Lson type to the equivalent Json type.
 *
 * Examples:
 *
 *   ToImmutable<42>                         // 42
 *   ToImmutable<'hi'>                       // 'hi'
 *   ToImmutable<number>                     // number
 *   ToImmutable<string>                     // string
 *   ToImmutable<string | LiveList<number>>  // string | readonly number[]
 *   ToImmutable<LiveMap<string, LiveList<number>>>
 *                                           // ReadonlyMap<string, readonly number[]>
 *   ToImmutable<LiveObject<{ a: number, b: LiveList<string>, c?: number }>>
 *                                           // { readonly a: null, readonly b: readonly string[], readonly c?: number }
 *
 */
type ToImmutable<L extends Lson | LsonObject> = L extends LiveList<infer I> ? readonly ToImmutable<I>[] : L extends LiveObject<infer O> ? ToImmutable<O> : L extends LiveMap<infer K, infer V> ? ReadonlyMap<K, ToImmutable<V>> : L extends LsonObject ? {
    readonly [K in keyof L]: ToImmutable<Exclude<L[K], undefined>> | (undefined extends L[K] ? undefined : never);
} : L extends Json ? L : never;
/**
 * Returns PlainLson for a given Json or LiveStructure, suitable for calling the storage init api
 */
declare function toPlainLson(lson: Lson): PlainLson;

/**
 * A LiveMap notification that is sent in-client to any subscribers whenever
 * one or more of the values inside the LiveMap instance have changed.
 */
type LiveMapUpdates<TKey extends string, TValue extends Lson> = {
    type: "LiveMap";
    node: LiveMap<TKey, TValue>;
    updates: {
        [key: string]: UpdateDelta;
    };
};
/**
 * The LiveMap class is similar to a JavaScript Map that is synchronized on all clients.
 * Keys should be a string, and values should be serializable to JSON.
 * If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner.
 */
declare class LiveMap<TKey extends string, TValue extends Lson> extends AbstractCrdt {
    #private;
    constructor(entries?: readonly (readonly [TKey, TValue])[] | undefined);
    /**
     * Returns a specified element from the LiveMap.
     * @param key The key of the element to return.
     * @returns The element associated with the specified key, or undefined if the key can't be found in the LiveMap.
     */
    get(key: TKey): TValue | undefined;
    /**
     * Adds or updates an element with a specified key and a value.
     * @param key The key of the element to add. Should be a string.
     * @param value The value of the element to add. Should be serializable to JSON.
     */
    set(key: TKey, value: TValue): void;
    /**
     * Returns the number of elements in the LiveMap.
     */
    get size(): number;
    /**
     * Returns a boolean indicating whether an element with the specified key exists or not.
     * @param key The key of the element to test for presence.
     */
    has(key: TKey): boolean;
    /**
     * Removes the specified element by key.
     * @param key The key of the element to remove.
     * @returns true if an element existed and has been removed, or false if the element does not exist.
     */
    delete(key: TKey): boolean;
    /**
     * Returns a new Iterator object that contains the [key, value] pairs for each element.
     */
    entries(): IterableIterator<[TKey, TValue]>;
    /**
     * Same function object as the initial value of the entries method.
     */
    [Symbol.iterator](): IterableIterator<[TKey, TValue]>;
    /**
     * Returns a new Iterator object that contains the keys for each element.
     */
    keys(): IterableIterator<TKey>;
    /**
     * Returns a new Iterator object that contains the values for each element.
     */
    values(): IterableIterator<TValue>;
    /**
     * Executes a provided function once per each key/value pair in the Map object, in insertion order.
     * @param callback Function to execute for each entry in the map.
     */
    forEach(callback: (value: TValue, key: TKey, map: LiveMap<TKey, TValue>) => void): void;
    toImmutable(): ReadonlyMap<TKey, ToImmutable<TValue>>;
    clone(): LiveMap<TKey, TValue>;
}

type StorageCallback = (updates: StorageUpdate[]) => void;
type LiveMapUpdate = LiveMapUpdates<string, Lson>;
type LiveObjectUpdate = LiveObjectUpdates<LsonObject>;
type LiveListUpdate = LiveListUpdates<Lson>;
/**
 * The payload of notifications sent (in-client) when LiveStructures change.
 * Messages of this kind are not originating from the network, but are 100%
 * in-client.
 */
type StorageUpdate = LiveMapUpdate | LiveObjectUpdate | LiveListUpdate;

/**
 * The managed pool is a namespace registry (i.e. a context) that "owns" all
 * the individual live nodes, ensuring each one has a unique ID, and holding on
 * to live nodes before and after they are inter-connected.
 */
interface ManagedPool {
    readonly roomId: string;
    readonly nodes: ReadonlyMap<string, LiveNode>;
    readonly generateId: () => string;
    readonly generateOpId: () => string;
    readonly getNode: (id: string) => LiveNode | undefined;
    readonly addNode: (id: string, node: LiveNode) => void;
    readonly deleteNode: (id: string) => void;
    /**
     * Dispatching has three responsibilities:
     * - Sends serialized ops to the WebSocket servers
     * - Add reverse operations to the undo/redo stack
     * - Notify room subscribers with updates (in-client, no networking)
     */
    dispatch: (ops: Op[], reverseOps: Op[], storageUpdates: Map<string, StorageUpdate>) => void;
    /**
     * Ensures storage can be written to else throws an error.
     * This is used to prevent writing to storage when the user does not have
     * permission to do so.
     * @throws {Error} if storage is not writable
     * @returns {void}
     */
    assertStorageIsWritable: () => void;
}
type CreateManagedPoolOptions = {
    /**
     * Returns the current connection ID. This is used to generate unique
     * prefixes for nodes created by this client. This number is allowed to
     * change over time (for example, when the client reconnects).
     */
    getCurrentConnectionId(): number;
    /**
     * Will get invoked when any Live structure calls .dispatch() on the pool.
     */
    onDispatch?: (ops: Op[], reverse: Op[], storageUpdates: Map<string, StorageUpdate>) => void;
    /**
     * Will get invoked when any Live structure calls .assertStorageIsWritable()
     * on the pool. Defaults to true when not provided. Return false if you want
     * to prevent writes to the pool locally early, because you know they won't
     * have an effect upstream.
     */
    isStorageWritable?: () => boolean;
};
/**
 * @private Private API, never use this API directly.
 */
declare function createManagedPool(roomId: string, options: CreateManagedPoolOptions): ManagedPool;
declare abstract class AbstractCrdt {
    #private;
    get roomId(): string | null;
    /**
     * Return an immutable snapshot of this Live node and its children.
     */
    toImmutable(): Immutable;
    /**
     * Returns a deep clone of the current LiveStructure, suitable for insertion
     * in the tree elsewhere.
     */
    abstract clone(): Lson;
}

type LiveListUpdateDelta = {
    type: "insert";
    index: number;
    item: Lson;
} | {
    type: "delete";
    index: number;
    deletedItem: Lson;
} | {
    type: "move";
    index: number;
    previousIndex: number;
    item: Lson;
} | {
    type: "set";
    index: number;
    item: Lson;
};
/**
 * A LiveList notification that is sent in-client to any subscribers whenever
 * one or more of the items inside the LiveList instance have changed.
 */
type LiveListUpdates<TItem extends Lson> = {
    type: "LiveList";
    node: LiveList<TItem>;
    updates: LiveListUpdateDelta[];
};
/**
 * The LiveList class represents an ordered collection of items that is synchronized across clients.
 */
declare class LiveList<TItem extends Lson> extends AbstractCrdt {
    #private;
    constructor(items: TItem[]);
    /**
     * Returns the number of elements.
     */
    get length(): number;
    /**
     * Adds one element to the end of the LiveList.
     * @param element The element to add to the end of the LiveList.
     */
    push(element: TItem): void;
    /**
     * Inserts one element at a specified index.
     * @param element The element to insert.
     * @param index The index at which you want to insert the element.
     */
    insert(element: TItem, index: number): void;
    /**
     * Move one element from one index to another.
     * @param index The index of the element to move
     * @param targetIndex The index where the element should be after moving.
     */
    move(index: number, targetIndex: number): void;
    /**
     * Deletes an element at the specified index
     * @param index The index of the element to delete
     */
    delete(index: number): void;
    clear(): void;
    set(index: number, item: TItem): void;
    /**
     * Returns an Array of all the elements in the LiveList.
     */
    toArray(): TItem[];
    /**
     * Tests whether all elements pass the test implemented by the provided function.
     * @param predicate Function to test for each element, taking two arguments (the element and its index).
     * @returns true if the predicate function returns a truthy value for every element. Otherwise, false.
     */
    every(predicate: (value: TItem, index: number) => unknown): boolean;
    /**
     * Creates an array with all elements that pass the test implemented by the provided function.
     * @param predicate Function to test each element of the LiveList. Return a value that coerces to true to keep the element, or to false otherwise.
     * @returns An array with the elements that pass the test.
     */
    filter(predicate: (value: TItem, index: number) => unknown): TItem[];
    /**
     * Returns the first element that satisfies the provided testing function.
     * @param predicate Function to execute on each value.
     * @returns The value of the first element in the LiveList that satisfies the provided testing function. Otherwise, undefined is returned.
     */
    find(predicate: (value: TItem, index: number) => unknown): TItem | undefined;
    /**
     * Returns the index of the first element in the LiveList that satisfies the provided testing function.
     * @param predicate Function to execute on each value until the function returns true, indicating that the satisfying element was found.
     * @returns The index of the first element in the LiveList that passes the test. Otherwise, -1.
     */
    findIndex(predicate: (value: TItem, index: number) => unknown): number;
    /**
     * Executes a provided function once for each element.
     * @param callbackfn Function to execute on each element.
     */
    forEach(callbackfn: (value: TItem, index: number) => void): void;
    /**
     * Get the element at the specified index.
     * @param index The index on the element to get.
     * @returns The element at the specified index or undefined.
     */
    get(index: number): TItem | undefined;
    /**
     * Returns the first index at which a given element can be found in the LiveList, or -1 if it is not present.
     * @param searchElement Element to locate.
     * @param fromIndex The index to start the search at.
     * @returns The first index of the element in the LiveList; -1 if not found.
     */
    indexOf(searchElement: TItem, fromIndex?: number): number;
    /**
     * Returns the last index at which a given element can be found in the LiveList, or -1 if it is not present. The LiveLsit is searched backwards, starting at fromIndex.
     * @param searchElement Element to locate.
     * @param fromIndex The index at which to start searching backwards.
     * @returns
     */
    lastIndexOf(searchElement: TItem, fromIndex?: number): number;
    /**
     * Creates an array populated with the results of calling a provided function on every element.
     * @param callback Function that is called for every element.
     * @returns An array with each element being the result of the callback function.
     */
    map<U>(callback: (value: TItem, index: number) => U): U[];
    /**
     * Tests whether at least one element in the LiveList passes the test implemented by the provided function.
     * @param predicate Function to test for each element.
     * @returns true if the callback function returns a truthy value for at least one element. Otherwise, false.
     */
    some(predicate: (value: TItem, index: number) => unknown): boolean;
    [Symbol.iterator](): IterableIterator<TItem>;
    toImmutable(): readonly ToImmutable<TItem>[];
    clone(): LiveList<TItem>;
}

/**
 * INTERNAL
 */
declare class LiveRegister<TValue extends Json> extends AbstractCrdt {
    #private;
    constructor(data: TValue);
    get data(): TValue;
    clone(): TValue;
}

type LiveStructure = LiveObject<LsonObject> | LiveList<Lson> | LiveMap<string, Lson>;
/**
 * Think of Lson as a sibling of the Json data tree, except that the nested
 * data structure can contain a mix of Json values and LiveStructure instances.
 */
type Lson = Json | LiveStructure;
/**
 * LiveNode is the internal tree for managing Live data structures. The key
 * difference with Lson is that all the Json values get represented in
 * a LiveRegister node.
 */
type LiveNode = LiveStructure | LiveRegister<Json>;
/**
 * A mapping of keys to Lson values. A Lson value is any valid JSON
 * value or a Live storage data structure (LiveMap, LiveList, etc.)
 */
type LsonObject = {
    [key: string]: Lson | undefined;
};
/**
 * Helper type to convert any valid Lson type to the equivalent Json type.
 *
 * Examples:
 *
 *   ToJson<42>                         // 42
 *   ToJson<'hi'>                       // 'hi'
 *   ToJson<number>                     // number
 *   ToJson<string>                     // string
 *   ToJson<string | LiveList<number>>  // string | number[]
 *   ToJson<LiveMap<string, LiveList<number>>>
 *                                      // { [key: string]: number[] }
 *   ToJson<LiveObject<{ a: number, b: LiveList<string>, c?: number }>>
 *                                      // { a: null, b: string[], c?: number }
 *
 */
type ToJson<T extends Lson | LsonObject> = T extends Json ? T : T extends LsonObject ? {
    [K in keyof T]: ToJson<Exclude<T[K], undefined>> | (undefined extends T[K] ? undefined : never);
} : T extends LiveList<infer I> ? ToJson<I>[] : T extends LiveObject<infer O> ? ToJson<O> : T extends LiveMap<infer KS, infer V> ? {
    [K in KS]: ToJson<V>;
} : never;

type DateToString<T> = {
    [P in keyof T]: T[P] extends Date ? string : T[P] extends Date | null ? string | null : T[P] extends Date | undefined ? string | undefined : T[P];
};

type InboxNotificationThreadData = {
    kind: "thread";
    id: string;
    roomId: string;
    threadId: string;
    notifiedAt: Date;
    readAt: Date | null;
};
type InboxNotificationTextMentionData = {
    kind: "textMention";
    id: string;
    roomId: string;
    notifiedAt: Date;
    readAt: Date | null;
    createdBy: string;
    mentionId: string;
};
type InboxNotificationTextMentionDataPlain = DateToString<InboxNotificationTextMentionData>;
type ActivityData = Record<string, string | boolean | number | undefined>;
type InboxNotificationActivity<K extends keyof DAD = keyof DAD> = {
    id: string;
    createdAt: Date;
    data: DAD[K];
};
type InboxNotificationCustomData<K extends keyof DAD = keyof DAD> = {
    kind: K;
    id: string;
    roomId?: string;
    subjectId: string;
    notifiedAt: Date;
    readAt: Date | null;
    activities: InboxNotificationActivity<K>[];
};
type InboxNotificationData = InboxNotificationThreadData | InboxNotificationCustomData | InboxNotificationTextMentionData;
type InboxNotificationThreadDataPlain = DateToString<InboxNotificationThreadData>;
type InboxNotificationCustomDataPlain = Omit<DateToString<InboxNotificationCustomData>, "activities"> & {
    activities: DateToString<InboxNotificationActivity>[];
};
type InboxNotificationDataPlain = InboxNotificationThreadDataPlain | InboxNotificationCustomDataPlain | InboxNotificationTextMentionDataPlain;
type InboxNotificationDeleteInfo = {
    type: "deletedInboxNotification";
    id: string;
    roomId: string;
    deletedAt: Date;
};

type BaseActivitiesData = {
    [key: `$${string}`]: ActivityData;
};

type BaseRoomInfo = {
    [key: string]: Json | undefined;
    /**
     * The name of the room.
     */
    name?: string;
    /**
     * The URL of the room.
     */
    url?: string;
};

declare global {
    /**
     * Namespace for user-defined Liveblocks types.
     */
    export interface Liveblocks {
        [key: string]: unknown;
    }
}
type ExtendableTypes = "Presence" | "Storage" | "UserMeta" | "RoomEvent" | "ThreadMetadata" | "RoomInfo" | "ActivitiesData";
type MakeErrorString<K extends ExtendableTypes, Reason extends string = "does not match its requirements"> = `The type you provided for '${K}' ${Reason}. To learn how to fix this, see https://liveblocks.io/docs/errors/${K}`;
type GetOverride<K extends ExtendableTypes, B, Reason extends string = "does not match its requirements"> = GetOverrideOrErrorValue<K, B, MakeErrorString<K, Reason>>;
type GetOverrideOrErrorValue<K extends ExtendableTypes, B, ErrorType> = unknown extends Liveblocks[K] ? B : Liveblocks[K] extends B ? Liveblocks[K] : ErrorType;
type DP = GetOverride<"Presence", JsonObject, "is not a valid JSON object">;
type DS = GetOverride<"Storage", LsonObject, "is not a valid LSON value">;
type DU = GetOverrideOrErrorValue<"UserMeta", BaseUserMeta, Record<"id" | "info", MakeErrorString<"UserMeta">>>;
type DE = GetOverride<"RoomEvent", Json, "is not a valid JSON value">;
type DM = GetOverride<"ThreadMetadata", BaseMetadata>;
type DRI = GetOverride<"RoomInfo", BaseRoomInfo>;
type DAD = GetOverrideOrErrorValue<"ActivitiesData", BaseActivitiesData, {
    [K in keyof Liveblocks["ActivitiesData"]]: "At least one of the custom notification kinds you provided for 'ActivitiesData' does not match its requirements. To learn how to fix this, see https://liveblocks.io/docs/errors/ActivitiesData";
}>;
type KDAD = keyof DAD extends `$${string}` ? keyof DAD : "Custom notification kinds must start with '$' but your custom 'ActivitiesData' type contains at least one kind which doesn't. To learn how to fix this, see https://liveblocks.io/docs/errors/ActivitiesData";

type BaseMetadata = Record<string, string | boolean | number | undefined>;
type CommentReaction = {
    emoji: string;
    createdAt: Date;
    users: {
        id: string;
    }[];
};
type CommentAttachment = {
    type: "attachment";
    id: string;
    name: string;
    size: number;
    mimeType: string;
};
type CommentLocalAttachmentIdle = {
    type: "localAttachment";
    status: "idle";
    id: string;
    name: string;
    size: number;
    mimeType: string;
    file: File;
};
type CommentLocalAttachmentUploading = {
    type: "localAttachment";
    status: "uploading";
    id: string;
    name: string;
    size: number;
    mimeType: string;
    file: File;
};
type CommentLocalAttachmentUploaded = {
    type: "localAttachment";
    status: "uploaded";
    id: string;
    name: string;
    size: number;
    mimeType: string;
    file: File;
};
type CommentLocalAttachmentError = {
    type: "localAttachment";
    status: "error";
    id: string;
    name: string;
    size: number;
    mimeType: string;
    file: File;
    error: Error;
};
type CommentLocalAttachment = CommentLocalAttachmentIdle | CommentLocalAttachmentUploading | CommentLocalAttachmentUploaded | CommentLocalAttachmentError;
type CommentMixedAttachment = CommentAttachment | CommentLocalAttachment;
/**
 * Represents a comment.
 */
type CommentData = {
    type: "comment";
    id: string;
    threadId: string;
    roomId: string;
    userId: string;
    createdAt: Date;
    editedAt?: Date;
    reactions: CommentReaction[];
    attachments: CommentAttachment[];
} & Relax<{
    body: CommentBody;
} | {
    deletedAt: Date;
}>;
type CommentDataPlain = Omit<DateToString<CommentData>, "reactions" | "body"> & {
    reactions: DateToString<CommentReaction>[];
} & Relax<{
    body: CommentBody;
} | {
    deletedAt: string;
}>;
type CommentBodyBlockElement = CommentBodyParagraph;
type CommentBodyInlineElement = CommentBodyText | CommentBodyMention | CommentBodyLink;
type CommentBodyElement = CommentBodyBlockElement | CommentBodyInlineElement;
type CommentBodyParagraph = {
    type: "paragraph";
    children: CommentBodyInlineElement[];
};
type CommentBodyMention = Relax<CommentBodyUserMention>;
type CommentBodyUserMention = {
    type: "mention";
    kind: "user";
    id: string;
};
type CommentBodyLink = {
    type: "link";
    url: string;
    text?: string;
};
type CommentBodyText = {
    bold?: boolean;
    italic?: boolean;
    strikethrough?: boolean;
    code?: boolean;
    text: string;
};
type CommentBody = {
    version: 1;
    content: CommentBodyBlockElement[];
};
type CommentUserReaction = {
    emoji: string;
    createdAt: Date;
    userId: string;
};
type CommentUserReactionPlain = DateToString<CommentUserReaction>;
/**
 * Represents a thread of comments.
 */
type ThreadData<M extends BaseMetadata = DM> = {
    type: "thread";
    id: string;
    roomId: string;
    createdAt: Date;
    updatedAt: Date;
    comments: CommentData[];
    metadata: M;
    resolved: boolean;
};
interface ThreadDataWithDeleteInfo<M extends BaseMetadata = DM> extends ThreadData<M> {
    deletedAt?: Date;
}
type ThreadDataPlain<M extends BaseMetadata> = Omit<DateToString<ThreadData<M>>, "comments" | "metadata"> & {
    comments: CommentDataPlain[];
    metadata: M;
};
type ThreadDeleteInfo = {
    type: "deletedThread";
    id: string;
    roomId: string;
    deletedAt: Date;
};
type StringOperators<T> = T | {
    startsWith: string;
};
/**
 * This type can be used to build a metadata query string (compatible
 * with `@liveblocks/query-parser`) through a type-safe API.
 *
 * In addition to exact values (`:` in query string), it adds:
 * - to strings:
 *  - `startsWith` (`^` in query string)
 */
type QueryMetadata<M extends BaseMetadata> = {
    [K in keyof M]: (string extends M[K] ? StringOperators<M[K]> : M[K]) | null;
};

/**
 * Pre-defined notification channels support list.
 */
type NotificationChannel = "email" | "slack" | "teams" | "webPush";
/**
 * `K` represents custom notification kinds
 * defined in the augmentation `ActivitiesData` (e.g `liveblocks.config.ts`).
 * It means the type `NotificationKind` will be shaped like:
 * thread | textMention | $customKind1 | $customKind2 | ...
 */
type NotificationKind<K extends keyof DAD = keyof DAD> = "thread" | "textMention" | K;
/**
 * A notification channel settings is a set of notification kinds.
 * One setting can have multiple kinds (+ augmentation)
 */
type NotificationChannelSettings = {
    [K in NotificationKind]: boolean;
};
/**
 * @private
 *
 * Base definition of notification settings.
 * Plain means it's a simple object coming from the remote backend.
 *
 * It's the raw settings object where somme channels cannot exists
 * because there are no notification kinds enabled on the dashboard.
 * And this object isn't yet proxied by the creator factory `createNotificationSettings`.
 */
type NotificationSettingsPlain = {
    [C in NotificationChannel]?: NotificationChannelSettings;
};
/**
 * Notification settings.
 * One channel for one set of settings.
 */
type NotificationSettings = {
    [C in NotificationChannel]: NotificationChannelSettings | null;
};
/**
 * It creates a deep partial specific for `NotificationSettings`
 * to offer a nice DX when updating the settings (e.g not being forced to define every keys)
 * and at the same the some preserver the augmentation for custom kinds (e.g `liveblocks.config.ts`).
 */
type DeepPartialWithAugmentation<T> = T extends object ? {
    [P in keyof T]?: T[P] extends {
        [K in NotificationKind]: boolean;
    } ? Partial<T[P]> & {
        [K in keyof DAD]?: boolean;
    } : DeepPartialWithAugmentation<T[P]>;
} : T;
/**
 * Partial notification settings with augmentation preserved gracefully.
 * It means you can update the settings without being forced to define every keys.
 * Useful when implementing update functions.
 */
type PartialNotificationSettings = DeepPartialWithAugmentation<NotificationSettingsPlain>;
/**
 * @private
 *
 * Creates a `NotificationSettings` object with the given initial plain settings.
 * It defines a getter for each channel to access the settings and returns `null` with an error log
 * in case the required channel isn't enabled in the dashboard.
 *
 * You can see this function as `Proxy` like around `NotificationSettingsPlain` type.
 * We can't predict what will be enabled on the dashboard or not, so it's important
 * provide a good DX to developers by returning `null` completed by an error log
 * when they try to access a channel that isn't enabled in the dashboard.
 */
declare function createNotificationSettings(plain: NotificationSettingsPlain): NotificationSettings;
/**
 * @private
 *
 * Patch a `NotificationSettings` object by applying notification kind updates
 * coming from a `PartialNotificationSettings` object.
 */
declare function patchNotificationSettings(existing: NotificationSettings, patch: PartialNotificationSettings): NotificationSettings;
/**
 *
 * Utility to check if a notification channel settings
 * is enabled for every notification kinds.
 *
 * Usage:
 * ```ts
 * const isEmailChannelEnabled = isNotificationChannelEnabled(settings.email);
 * ```
 */
declare function isNotificationChannelEnabled(settings: NotificationChannelSettings | null): boolean;

type RoomThreadsSubscriptionSettings = "all" | "replies_and_mentions" | "none";
type RoomTextMentionsSubscriptionSettings = "mine" | "none";
type RoomSubscriptionSettings = {
    threads: RoomThreadsSubscriptionSettings;
    textMentions: RoomTextMentionsSubscriptionSettings;
};
type UserRoomSubscriptionSettings = {
    roomId: string;
} & RoomSubscriptionSettings;

type SubscriptionData<K extends keyof DAD = keyof DAD> = {
    kind: NotificationKind<K>;
    subjectId: string;
    createdAt: Date;
};
type SubscriptionDataPlain = DateToString<SubscriptionData>;
type UserSubscriptionData<K extends keyof DAD = keyof DAD> = SubscriptionData<K> & {
    userId: string;
};
type UserSubscriptionDataPlain = DateToString<UserSubscriptionData>;
type SubscriptionDeleteInfo = {
    type: "deletedSubscription";
    kind: NotificationKind;
    subjectId: string;
    deletedAt: Date;
};
type SubscriptionDeleteInfoPlain = DateToString<SubscriptionDeleteInfo>;
type SubscriptionKey = `${NotificationKind}:${string}`;
declare function getSubscriptionKey(subscription: SubscriptionData | SubscriptionDeleteInfo): SubscriptionKey;
declare function getSubscriptionKey(kind: NotificationKind, subjectId: string): SubscriptionKey;

/**
 * Represents a user connected in a room. Treated as immutable.
 */
type User<P extends JsonObject = DP, U extends BaseUserMeta = DU> = {
    /**
     * The connection ID of the User. It is unique and increment at every new connection.
     */
    readonly connectionId: number;
    /**
     * The ID of the User that has been set in the authentication endpoint.
     * Useful to get additional information about the connected user.
     */
    readonly id: U["id"];
    /**
     * Additional user information that has been set in the authentication endpoint.
     */
    readonly info: U["info"];
    /**
     * The user’s presence data.
     */
    readonly presence: P;
    /**
     * True if the user can mutate the Room’s Storage and/or YDoc, false if they
     * can only read but not mutate it.
     */
    readonly canWrite: boolean;
    /**
     * True if the user can comment on a thread
     */
    readonly canComment: boolean;
};

type InternalOthersEvent<P extends JsonObject, U extends BaseUserMeta> = Relax<{
    type: "leave";
    user: User<P, U>;
} | {
    type: "enter";
    user: User<P, U>;
} | {
    type: "update";
    user: User<P, U>;
    updates: Partial<P>;
} | {
    type: "reset";
}>;
type OthersEvent<P extends JsonObject = DP, U extends BaseUserMeta = DU> = Resolve<InternalOthersEvent<P, U> & {
    others: readonly User<P, U>[];
}>;
declare enum TextEditorType {
    Lexical = "lexical",
    TipTap = "tiptap",
    BlockNote = "blocknote"
}

type OptionalKeys<T> = {
    [K in keyof T]-?: undefined extends T[K] ? K : never;
}[keyof T];
type MakeOptionalFieldsNullable<T> = {
    [K in keyof T]: K extends OptionalKeys<T> ? T[K] | null : T[K];
};
type Patchable<T> = Partial<MakeOptionalFieldsNullable<T>>;

interface RoomHttpApi<M extends BaseMetadata> {
    getThreads(options: {
        roomId: string;
        cursor?: string;
        query?: {
            resolved?: boolean;
            metadata?: Partial<QueryMetadata<M>>;
        };
    }): Promise<{
        threads: ThreadData<M>[];
        inboxNotifications: InboxNotificationData[];
        subscriptions: SubscriptionData[];
        requestedAt: Date;
        nextCursor: string | null;
        permissionHints: Record<string, Permission[]>;
    }>;
    getThreadsSince(options: {
        roomId: string;
        since: Date;
        signal?: AbortSignal;
    }): Promise<{
        threads: {
            updated: ThreadData<M>[];
            deleted: ThreadDeleteInfo[];
        };
        inboxNotifications: {
            updated: InboxNotificationData[];
            deleted: InboxNotificationDeleteInfo[];
        };
        subscriptions: {
            updated: SubscriptionData[];
            deleted: SubscriptionDeleteInfo[];
        };
        requestedAt: Date;
        permissionHints: Record<string, Permission[]>;
    }>;
    createThread({ roomId, metadata, body, commentId, threadId, attachmentIds, }: {
        roomId: string;
        threadId?: string;
        commentId?: string;
        metadata: M | undefined;
        body: CommentBody;
        attachmentIds?: string[];
    }): Promise<ThreadData<M>>;
    getThread(options: {
        roomId: string;
        threadId: string;
    }): Promise<{
        thread?: ThreadData<M>;
        inboxNotification?: InboxNotificationData;
        subscription?: SubscriptionData;
    }>;
    deleteThread({ roomId, threadId, }: {
        roomId: string;
        threadId: string;
    }): Promise<void>;
    editThreadMetadata({ roomId, metadata, threadId, }: {
        roomId: string;
        metadata: Patchable<M>;
        threadId: string;
    }): Promise<M>;
    createComment({ roomId, threadId, commentId, body, attachmentIds, }: {
        roomId: string;
        threadId: string;
        commentId?: string;
        body: CommentBody;
        attachmentIds?: string[];
    }): Promise<CommentData>;
    editComment({ roomId, threadId, commentId, body, attachmentIds, }: {
        roomId: string;
        threadId: string;
        commentId: string;
        body: CommentBody;
        attachmentIds?: string[];
    }): Promise<CommentData>;
    deleteComment({ roomId, threadId, commentId, }: {
        roomId: string;
        threadId: string;
        commentId: string;
    }): Promise<void>;
    addReaction({ roomId, threadId, commentId, emoji, }: {
        roomId: string;
        threadId: string;
        commentId: string;
        emoji: string;
    }): Promise<CommentUserReaction>;
    removeReaction({ roomId, threadId, commentId, emoji, }: {
        roomId: string;
        threadId: string;
        commentId: string;
        emoji: string;
    }): Promise<void>;
    markThreadAsResolved({ roomId, threadId, }: {
        roomId: string;
        threadId: string;
    }): Promise<void>;
    markThreadAsUnresolved({ roomId, threadId, }: {
        roomId: string;
        threadId: string;
    }): Promise<void>;
    subscribeToThread({ roomId, threadId, }: {
        roomId: string;
        threadId: string;
    }): Promise<SubscriptionData>;
    unsubscribeFromThread({ roomId, threadId, }: {
        roomId: string;
        threadId: string;
    }): Promise<void>;
    markRoomInboxNotificationAsRead({ roomId, inboxNotificationId, }: {
        roomId: string;
        inboxNotificationId: string;
    }): Promise<string>;
    getSubscriptionSettings({ roomId, signal, }: {
        roomId: string;
        signal?: AbortSignal;
    }): Promise<RoomSubscriptionSettings>;
    updateSubscriptionSettings({ roomId, settings, }: {
        roomId: string;
        settings: Partial<RoomSubscriptionSettings>;
    }): Promise<RoomSubscriptionSettings>;
    getAttachmentUrl(options: {
        roomId: string;
        attachmentId: string;
    }): Promise<string>;
    uploadAttachment({ roomId, attachment, signal, }: {
        roomId: string;
        attachment: CommentLocalAttachment;
        signal?: AbortSignal;
    }): Promise<CommentAttachment>;
    getOrCreateAttachmentUrlsStore(roomId: string): BatchStore<string, string>;
    uploadChatAttachment({ chatId, attachment, signal, }: {
        chatId: string;
        attachment: {
            id: string;
            file: File;
        };
        signal?: AbortSignal;
    }): Promise<void>;
    getOrCreateChatAttachmentUrlsStore(chatId: string): BatchStore<string, string>;
    getChatAttachmentUrl(options: {
        attachmentId: string;
    }): Promise<string>;
    createTextMention({ roomId, userId, mentionId, }: {
        roomId: string;
        userId: string;
        mentionId: string;
    }): Promise<void>;
    deleteTextMention({ roomId, mentionId, }: {
        roomId: string;
        mentionId: string;
    }): Promise<void>;
    getTextVersion({ roomId, versionId, }: {
        roomId: string;
        versionId: string;
    }): Promise<Response>;
    createTextVersion({ roomId }: {
        roomId: string;
    }): Promise<void>;
    reportTextEditor({ roomId, type, rootKey, }: {
        roomId: string;
        type: TextEditorType;
        rootKey: string;
    }): Promise<void>;
    listTextVersions({ roomId }: {
        roomId: string;
    }): Promise<{
        versions: {
            type: "historyVersion";
            kind: "yjs";
            id: string;
            authors: {
                id: string;
            }[];
            createdAt: Date;
        }[];
        requestedAt: Date;
    }>;
    listTextVersionsSince({ roomId, since, signal, }: {
        roomId: string;
        since: Date;
        signal?: AbortSignal;
    }): Promise<{
        versions: {
            type: "historyVersion";
            kind: "yjs";
            id: string;
            authors: {
                id: string;
            }[];
            createdAt: Date;
        }[];
        requestedAt: Date;
    }>;
    streamStorage(options: {
        roomId: string;
    }): Promise<IdTuple<SerializedCrdt>[]>;
    sendMessages<P extends JsonObject, E extends Json>(options: {
        roomId: string;
        nonce: string | undefined;
        messages: ClientMsg<P, E>[];
    }): Promise<Response>;
    executeContextualPrompt({ roomId, prompt, context, signal, }: {
        roomId: string;
        prompt: string;
        context: ContextualPromptContext;
        previous?: {
            prompt: string;
            response: ContextualPromptResponse;
        };
        signal: AbortSignal;
    }): Promise<string>;
}
interface NotificationHttpApi<M extends BaseMetadata> {
    getInboxNotifications(options?: {
        cursor?: string;
    }): Promise<{
        inboxNotifications: InboxNotificationData[];
        threads: ThreadData<M>[];
        subscriptions: SubscriptionData[];
        nextCursor: string | null;
        requestedAt: Date;
    }>;
    getInboxNotificationsSince(options: {
        since: Date;
        signal?: AbortSignal;
    }): Promise<{
        inboxNotifications: {
            updated: InboxNotificationData[];
            deleted: InboxNotificationDeleteInfo[];
        };
        threads: {
            updated: ThreadData<M>[];
            deleted: ThreadDeleteInfo[];
        };
        subscriptions: {
            updated: SubscriptionData[];
            deleted: SubscriptionDeleteInfo[];
        };
        requestedAt: Date;
    }>;
    getUnreadInboxNotificationsCount(): Promise<number>;
    markAllInboxNotificationsAsRead(): Promise<void>;
    markInboxNotificationAsRead(inboxNotificationId: string): Promise<void>;
    deleteAllInboxNotifications(): Promise<void>;
    deleteInboxNotification(inboxNotificationId: string): Promise<void>;
    getNotificationSettings(options?: {
        signal?: AbortSignal;
    }): Promise<NotificationSettingsPlain>;
    updateNotificationSettings(settings: PartialNotificationSettings): Promise<NotificationSettingsPlain>;
}
interface LiveblocksHttpApi<M extends BaseMetadata> extends RoomHttpApi<M>, NotificationHttpApi<M> {
    getUserThreads_experimental(options?: {
        cursor?: string;
        query?: {
            resolved?: boolean;
            metadata?: Partial<QueryMetadata<M>>;
        };
    }): Promise<{
        threads: ThreadData<M>[];
        inboxNotifications: InboxNotificationData[];
        subscriptions: SubscriptionData[];
        nextCursor: string | null;
        requestedAt: Date;
        permissionHints: Record<string, Permission[]>;
    }>;
    getUserThreadsSince_experimental(options: {
        since: Date;
        signal?: AbortSignal;
    }): Promise<{
        inboxNotifications: {
            updated: InboxNotificationData[];
            deleted: InboxNotificationDeleteInfo[];
        };
        threads: {
            updated: ThreadData<M>[];
            deleted: ThreadDeleteInfo[];
        };
        subscriptions: {
            updated: SubscriptionData[];
            deleted: SubscriptionDeleteInfo[];
        };
        requestedAt: Date;
        permissionHints: Record<string, Permission[]>;
    }>;
}

/**
 * Use this symbol to brand an object property as internal.
 *
 * @example
 * Object.defineProperty(
 *   {
 *     public,
 *     [kInternal]: {
 *       private
 *     },
 *   },
 *   kInternal,
 *   {
 *     enumerable: false,
 *   }
 * );
 */
declare const kInternal: unique symbol;

/**
 * Back-port of TypeScript 5.4's built-in NoInfer utility type.
 * See https://stackoverflow.com/a/56688073/148872
 */
type NoInfr<A> = [A][A extends any ? 0 : never];

type Awaitable<T> = T | PromiseLike<T>;

type AiConnectionErrorContext = {
    type: "AI_CONNECTION_ERROR";
    code: -1 | 4001 | (number & {});
};
type RoomConnectionErrorContext = {
    type: "ROOM_CONNECTION_ERROR";
    code: -1 | 4001 | 4005 | 4006 | (number & {});
    roomId: string;
};
type CommentsOrNotificationsErrorContext = {
    type: "CREATE_THREAD_ERROR";
    roomId: string;
    threadId: string;
    commentId: string;
    body: CommentBody;
    metadata: BaseMetadata;
} | {
    type: "DELETE_THREAD_ERROR";
    roomId: string;
    threadId: string;
} | {
    type: "EDIT_THREAD_METADATA_ERROR";
    roomId: string;
    threadId: string;
    metadata: Patchable<BaseMetadata>;
} | {
    type: "MARK_THREAD_AS_RESOLVED_ERROR" | "MARK_THREAD_AS_UNRESOLVED_ERROR" | "SUBSCRIBE_TO_THREAD_ERROR" | "UNSUBSCRIBE_FROM_THREAD_ERROR";
    roomId: string;
    threadId: string;
} | {
    type: "CREATE_COMMENT_ERROR" | "EDIT_COMMENT_ERROR";
    roomId: string;
    threadId: string;
    commentId: string;
    body: CommentBody;
} | {
    type: "DELETE_COMMENT_ERROR";
    roomId: string;
    threadId: string;
    commentId: string;
} | {
    type: "ADD_REACTION_ERROR" | "REMOVE_REACTION_ERROR";
    roomId: string;
    threadId: string;
    commentId: string;
    emoji: string;
} | {
    type: "MARK_INBOX_NOTIFICATION_AS_READ_ERROR";
    inboxNotificationId: string;
    roomId?: string;
} | {
    type: "DELETE_INBOX_NOTIFICATION_ERROR";
    inboxNotificationId: string;
} | {
    type: "MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR" | "DELETE_ALL_INBOX_NOTIFICATIONS_ERROR";
} | {
    type: "UPDATE_ROOM_SUBSCRIPTION_SETTINGS_ERROR";
    roomId: string;
} | {
    type: "UPDATE_NOTIFICATION_SETTINGS_ERROR";
};
type LiveblocksErrorContext = Relax<RoomConnectionErrorContext | CommentsOrNotificationsErrorContext | AiConnectionErrorContext>;
declare class LiveblocksError extends Error {
    readonly context: LiveblocksErrorContext;
    constructor(message: string, context: LiveblocksErrorContext, cause?: Error);
    /** Convenience accessor for error.context.roomId (if available) */
    get roomId(): LiveblocksErrorContext["roomId"];
    /**
     * Creates a LiveblocksError from a generic error, by attaching Liveblocks
     * contextual information like room ID, thread ID, etc.
     */
    static from(context: LiveblocksErrorContext, cause?: Error): LiveblocksError;
}

type MentionData = Relax<UserMentionData>;
type UserMentionData = {
    kind: "user";
    id: string;
};

type ResolveMentionSuggestionsArgs = {
    /**
     * The ID of the current room.
     */
    roomId: string;
    /**
     * The text to search for.
     */
    text: string;
};
type ResolveUsersArgs = {
    /**
     * The IDs of the users to resolve.
     */
    userIds: string[];
};
type ResolveRoomsInfoArgs = {
    /**
     * The IDs of the rooms to resolve.
     */
    roomIds: string[];
};
type EnterOptions<P extends JsonObject = DP, S extends LsonObject = DS> = Resolve<{
    /**
     * Whether or not the room automatically connects to Liveblock servers.
     * Default is true.
     *
     * Usually set to false when the client is used from the server to not call
     * the authentication endpoint or connect via WebSocket.
     */
    autoConnect?: boolean;
} & PartialUnless<P, {
    /**
     * The initial Presence to use and announce when you enter the Room. The
     * Presence is available on all users in the Room (me & others).
     */
    initialPresence: P | ((roomId: string) => P);
}> & PartialUnless<S, {
    /**
     * The initial Storage to use when entering a new Room.
     */
    initialStorage: S | ((roomId: string) => S);
}>>;
type SyncStatus = "synchronizing" | "synchronized";
/**
 * "synchronizing"     - Liveblocks is in the process of writing changes
 * "synchronized"      - Liveblocks has persisted all pending changes
 * "has-local-changes" - There is local pending state inputted by the user, but
 *                       we're not yet "synchronizing" it until a user
 *                       interaction, like the draft text in a comment box.
 */
type InternalSyncStatus = SyncStatus | "has-local-changes";
/**
 * @private
 *
 * Private methods and variables used in the core internals, but as a user
 * of Liveblocks, NEVER USE ANY OF THESE DIRECTLY, because bad things
 * will probably happen if you do.
 */
type PrivateClientApi<U extends BaseUserMeta, M extends BaseMetadata> = {
    readonly currentUserId: Signal<string | undefined>;
    readonly mentionSuggestionsCache: Map<string, MentionData[]>;
    readonly resolveMentionSuggestions: ClientOptions<U>["resolveMentionSuggestions"];
    readonly usersStore: BatchStore<U["info"] | undefined, string>;
    readonly roomsInfoStore: BatchStore<DRI | undefined, string>;
    readonly getRoomIds: () => string[];
    readonly httpClient: LiveblocksHttpApi<M>;
    as<M2 extends BaseMetadata>(): Client<U, M2>;
    createSyncSource(): SyncSource;
    emitError(context: LiveblocksErrorContext, cause?: Error): void;
    ai: Ai;
};
type NotificationsApi<M extends BaseMetadata> = {
    /**
     * Gets a page (or the initial page) for user inbox notifications and their
     * associated threads and thread subscriptions.
     *
     * This function should NOT be used for delta updates, only for pagination
     * (including the first page fetch). For delta updates (done during the
     * periodic polling), use the `getInboxNotificationsSince` function.
     *
     * @example
     * const {
     *   inboxNotifications,
     *   threads,
     *   subscriptions,
     *   nextCursor,
     * } = await client.getInboxNotifications();
     * const data = await client.getInboxNotifications();  // Fetch initial page (of 20 inbox notifications)
     * const data = await client.getInboxNotifications({ cursor: nextCursor });  // Fetch next page (= next 20 inbox notifications)
     */
    getInboxNotifications(options?: {
        cursor?: string;
    }): Promise<{
        inboxNotifications: InboxNotificationData[];
        threads: ThreadData<M>[];
        subscriptions: SubscriptionData[];
        nextCursor: string | null;
        requestedAt: Date;
    }>;
    /**
     * Fetches a "delta update" since the last time we updated.
     *
     * This function should NOT be used for pagination, for that, see the
     * `getInboxNotifications` function.
     *
     * @example
     * const {
     *   inboxNotifications: {
     *     updated,
     *     deleted,
     *   },
     *   threads: {
     *     updated,
     *     deleted,
     *   },
     *   subscriptions: {
     *     updated,
     *     deleted,
     *   },
     *   requestedAt,
     * } = await client.getInboxNotificationsSince({ since: result.requestedAt }});
     */
    getInboxNotificationsSince(options: {
        since: Date;
        signal?: AbortSignal;
    }): Promise<{
        inboxNotifications: {
            updated: InboxNotificationData[];
            deleted: InboxNotificationDeleteInfo[];
        };
        threads: {
            updated: ThreadData<M>[];
            deleted: ThreadDeleteInfo[];
        };
        subscriptions: {
            updated: SubscriptionData[];
            deleted: SubscriptionDeleteInfo[];
        };
        requestedAt: Date;
    }>;
    /**
     * Gets the number of unread inbox notifications for the current user.
     *
     * @example
     * const count = await client.getUnreadInboxNotificationsCount();
     */
    getUnreadInboxNotificationsCount(): Promise<number>;
    /**
     * Marks all inbox notifications as read.
     *
     * @example
     * await client.markAllInboxNotificationsAsRead();
     */
    markAllInboxNotificationsAsRead(): Promise<void>;
    /**
     * Marks an inbox notification as read.
     *
     * @example
     * await client.markInboxNotificationAsRead("in_xxx");
     */
    markInboxNotificationAsRead(inboxNotificationId: string): Promise<void>;
    /**
     * Deletes all inbox notifications for the current user.
     *
     * @example
     * await client.deleteAllInboxNotifications();
     */
    deleteAllInboxNotifications(): Promise<void>;
    /**
     * Deletes an inbox notification for the current user.
     *
     * @example
     * await client.deleteInboxNotification("in_xxx");
     */
    deleteInboxNotification(inboxNotificationId: string): Promise<void>;
    /**
     * Gets notifications settings for a user for a project.
     *
     * @example
     * const notificationSettings = await client.getNotificationSettings();
     */
    getNotificationSettings(options?: {
        signal?: AbortSignal;
    }): Promise<NotificationSettings>;
    /**
     * Update notifications settings for a user for a project.
     *
     * @example
     * await client.updateNotificationSettings({
     *  email: {
     *    thread: true,
     *    textMention: false,
     *    $customKind1: true,
     *  }
     * })
     */
    updateNotificationSettings(settings: PartialNotificationSettings): Promise<NotificationSettings>;
};
/**
 * @private Widest-possible Client type, matching _any_ Client instance. Note
 * that this type is different from `Client`-without-type-arguments. That
 * represents a Client instance using globally augmented types only, which is
 * narrower.
 */
type OpaqueClient = Client<BaseUserMeta>;
type Client<U extends BaseUserMeta = DU, M extends BaseMetadata = DM> = {
    /**
     * Gets a room. Returns null if {@link Client.enter} has not been called previously.
     *
     * @param roomId The id of the room
     */
    getRoom<P extends JsonObject = DP, S extends LsonObject = DS, E extends Json = DE, M2 extends BaseMetadata = M>(roomId: string): Room<P, S, U, E, M2> | null;
    /**
     * Enter a room.
     * @param roomId The id of the room
     * @param options Optional. You can provide initializers for the Presence or Storage when entering the Room.
     * @returns The room and a leave function. Call the returned leave() function when you no longer need the room.
     */
    enterRoom<P extends JsonObject = DP, S extends LsonObject = DS, E extends Json = DE, M2 extends BaseMetadata = M>(roomId: string, ...args: OptionalTupleUnless<P & S, [
        options: EnterOptions<NoInfr<P>, NoInfr<S>>
    ]>): {
        room: Room<P, S, U, E, M2>;
        leave: () => void;
    };
    /**
     * Purges all cached auth tokens and reconnects all rooms that are still
     * connected, if any.
     *
     * Call this whenever you log out a user in your application.
     */
    logout(): void;
    /**
     * Advanced APIs related to the resolvers.
     */
    resolvers: {
        /**
         * Invalidate some or all users that were previously cached by `resolveUsers`.
         *
         * @example
         * // Invalidate all users
         * client.resolvers.invalidateUsers();
         *
         * @example
         * // Invalidate specific users
         * client.resolvers.invalidateUsers(["user-1", "user-2"]);
         */
        invalidateUsers(userIds?: string[]): void;
        /**
         * Invalidate some or all rooms info that were previously cached by `resolveRoomsInfo`.
         *
         * @example
         * // Invalidate all rooms
         * client.resolvers.invalidateRoomsInfo();
         *
         * @example
         * // Invalidate specific rooms
         * client.resolvers.invalidateRoomsInfo(["room-1", "room-2"]);
         */
        invalidateRoomsInfo(roomIds?: string[]): void;
        /**
         * Invalidate all mention suggestions cached by `resolveMentionSuggestions`.
         *
         * @example
         * // Invalidate all mention suggestions
         * client.resolvers.invalidateMentionSuggestions();
         */
        invalidateMentionSuggestions(): void;
    };
    /**
     * @private
     *
     * Private methods and variables used in the core internals, but as a user
     * of Liveblocks, NEVER USE ANY OF THESE DIRECTLY, because bad things
     * will probably happen if you do.
     */
    readonly [kInternal]: PrivateClientApi<U, M>;
    /**
     * Returns the current global sync status of the Liveblocks client. If any
     * part of Liveblocks has any local pending changes that haven't been
     * confirmed by or persisted by the server yet, this will be "synchronizing",
     * otherwise "synchronized".
     *
     * This is a combined status for all of the below parts of Liveblocks:
     * - Storage (realtime APIs)
     * - Text Editors
     * - Comments
     * - Notifications
     *
     * @example
     * const status = client.getSyncStatus();  // "synchronizing" | "synchronized"
     */
    getSyncStatus(): SyncStatus;
    /**
     * All possible client events, subscribable from a single place.
     */
    readonly events: {
        readonly error: Observable<LiveblocksError>;
        readonly syncStatus: Observable<void>;
    };
} & NotificationsApi<M>;
type AuthEndpoint = string | ((room?: string) => Promise<CustomAuthenticationResult>);
/**
 * The authentication endpoint that is called to ensure that the current user has access to a room.
 * Can be an url or a callback if you need to add additional headers.
 */
type ClientOptions<U extends BaseUserMeta = DU> = {
    throttle?: number;
    lostConnectionTimeout?: number;
    backgroundKeepAliveTimeout?: number;
    polyfills?: Polyfills;
    largeMessageStrategy?: LargeMessageStrategy;
    unstable_streamData?: boolean;
    /**
     * A function that returns a list of mention suggestions matching a string.
     */
    resolveMentionSuggestions?: (args: ResolveMentionSuggestionsArgs) => Awaitable<string[] | MentionData[]>;
    /**
     * A function that returns user info from user IDs.
     * You should return a list of user objects of the same size, in the same order.
     */
    resolveUsers?: (args: ResolveUsersArgs) => Awaitable<(U["info"] | undefined)[] | undefined>;
    /**
     * A function that returns room info from room IDs.
     * You should return a list of room info objects of the same size, in the same order.
     */
    resolveRoomsInfo?: (args: ResolveRoomsInfoArgs) => Awaitable<(DRI | undefined)[] | undefined>;
    /**
     * Prevent the current browser tab from being closed if there are any locally
     * pending Liveblocks changes that haven't been submitted to or confirmed by
     * the server yet.
     */
    preventUnsavedChanges?: boolean;
} & Relax<{
    publicApiKey: string;
} | {
    authEndpoint: AuthEndpoint;
}>;
/**
 * Create a client that will be responsible to communicate with liveblocks servers.
 *
 * @example
 * const client = createClient({
 *   authEndpoint: "/api/auth"
 * });
 *
 * // It's also possible to use a function to call your authentication endpoint.
 * // Useful to add additional headers or use an API wrapper (like Firebase functions)
 * const client = createClient({
 *   authEndpoint: async (room?) => {
 *     const response = await fetch("/api/auth", {
 *       method: "POST",
 *       headers: {
 *          Authentication: "token",
 *          "Content-Type": "application/json"
 *       },
 *       body: JSON.stringify({ room })
 *     });
 *
 *     return await response.json(); // should be: { token: "..." }
 *   }
 * });
 */
declare function createClient<U extends BaseUserMeta = DU>(options: ClientOptions<U>): Client<U>;
/**
 * @private Private API, don't use this directly.
 */
declare function checkBounds(option: string, value: unknown, min: number, max?: number, recommendedMin?: number): number;

interface IWebSocketEvent {
    type: string;
}
interface IWebSocketCloseEvent extends IWebSocketEvent {
    readonly code: WebsocketCloseCodes;
    readonly wasClean: boolean;
    readonly reason: string;
}
interface IWebSocketMessageEvent extends IWebSocketEvent {
    readonly data: string | Buffer | ArrayBuffer | readonly Buffer[];
}
interface IWebSocketInstance {
    readonly CONNECTING: number;
    readonly OPEN: number;
    readonly CLOSING: number;
    readonly CLOSED: number;
    readonly readyState: number;
    addEventListener(type: "close", listener: (this: IWebSocketInstance, ev: IWebSocketCloseEvent) => unknown): void;
    addEventListener(type: "message", listener: (this: IWebSocketInstance, ev: IWebSocketMessageEvent) => unknown): void;
    addEventListener(type: "open" | "error", listener: (this: IWebSocketInstance, ev: IWebSocketEvent) => unknown): void;
    removeEventListener(type: "close", listener: (this: IWebSocketInstance, ev: IWebSocketCloseEvent) => unknown): void;
    removeEventListener(type: "message", listener: (this: IWebSocketInstance, ev: IWebSocketMessageEvent) => unknown): void;
    removeEventListener(type: "open" | "error", listener: (this: IWebSocketInstance, ev: IWebSocketEvent) => unknown): void;
    close(): void;
    send(data: string): void;
}
/**
 * Either the browser-based WebSocket API or Node.js' WebSocket API (from the
 * 'ws' package).
 *
 * This type defines the minimal WebSocket API that Liveblocks needs from
 * a WebSocket implementation, and is a minimal subset of the browser-based
 * WebSocket APIs and Node.js' WebSocket API so that both implementations are
 * assignable to this type.
 */
interface IWebSocket {
    new (address: string): IWebSocketInstance;
}
/**
 * The following ranges will be respected by the client:
 *
 *   10xx: client will reauthorize (just like 41xx)
 *   40xx: client will disconnect
 *   41xx: client will reauthorize
 *   42xx: client will retry without reauthorizing (currently not used)
 *
 */
declare enum WebsocketCloseCodes {
    /** Normal close of connection, the connection fulfilled its purpose. */
    CLOSE_NORMAL = 1000,
    /** Unexpected error happened with the network/infra level. In spirit akin to HTTP 503 */
    CLOSE_ABNORMAL = 1006,
    /** Unexpected error happened. In spirit akin to HTTP 500 */
    UNEXPECTED_CONDITION = 1011,
    /** Please back off for now, but try again in a few moments */
    TRY_AGAIN_LATER = 1013,
    /** Message wasn't understood, disconnect */
    INVALID_MESSAGE_FORMAT = 4000,
    /** Server refused to allow connection. Re-authorizing won't help. Disconnect. In spirit akin to HTTP 403 */
    NOT_ALLOWED = 4001,
    /** Unused */
    MAX_NUMBER_OF_MESSAGES_PER_SECONDS = 4002,
    /** Unused */
    MAX_NUMBER_OF_CONCURRENT_CONNECTIONS = 4003,
    /** Unused */
    MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP = 4004,
    /** Room is full, disconnect */
    MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM = 4005,
    /** The room's ID was updated, disconnect */
    ROOM_ID_UPDATED = 4006,
    /** The server kicked the connection from the room. */
    KICKED = 4100,
    /** The auth token is expired, reauthorize to get a fresh one. In spirit akin to HTTP 401 */
    TOKEN_EXPIRED = 4109,
    /** Disconnect immediately */
    CLOSE_WITHOUT_RETRY = 4999
}

/**
 * Returns a human-readable status indicating the current connection status of
 * a Room, as returned by `room.getStatus()`. Can be used to implement
 * a connection status badge.
 */
type Status = "initial" | "connecting" | "connected" | "reconnecting" | "disconnected";
/**
 * Used to report about app-level reconnection issues.
 *
 * Normal (quick) reconnects won't be reported as a "lost connection". Instead,
 * the application will only get an event if the reconnection attempts by the
 * client are taking (much) longer than usual. Definitely a situation you want
 * to inform your users about, for example, by throwing a toast message on
 * screen, or show a "trying to reconnect" banner.
 */
type LostConnectionEvent = "lost" | "restored" | "failed";
/**
 * Arbitrary record that will be used as the authentication "authValue". It's the
 * value that is returned by calling the authentication delegate, and will get
 * passed to the connection factory delegate. This value will be remembered by
 * the connection manager, but its value will not be interpreted, so it can be
 * any value (except null).
 */
type BaseAuthResult = NonNullable<Json>;
type Delegates<T extends BaseAuthResult> = {
    authenticate: () => Promise<T>;
    createSocket: (authValue: T) => IWebSocketInstance;
    canZombie: () => boolean;
};

declare enum ServerMsgCode {
    UPDATE_PRESENCE = 100,
    USER_JOINED = 101,
    USER_LEFT = 102,
    BROADCASTED_EVENT = 103,
    ROOM_STATE = 104,
    INITIAL_STORAGE_STATE = 200,
    UPDATE_STORAGE = 201,
    REJECT_STORAGE_OP = 299,
    UPDATE_YDOC = 300,
    THREAD_CREATED = 400,
    THREAD_DELETED = 407,
    THREAD_METADATA_UPDATED = 401,
    THREAD_UPDATED = 408,
    COMMENT_CREATED = 402,
    COMMENT_EDITED = 403,
    COMMENT_DELETED = 404,
    COMMENT_REACTION_ADDED = 405,
    COMMENT_REACTION_REMOVED = 406
}
/**
 * Messages that can be sent from the server to the client.
 */
type ServerMsg<P extends JsonObject, U extends BaseUserMeta, E extends Json> = UpdatePresenceServerMsg<P> | UserJoinServerMsg<U> | UserLeftServerMsg | BroadcastedEventServerMsg<E> | RoomStateServerMsg<U> | InitialDocumentStateServerMsg | UpdateStorageServerMsg | RejectedStorageOpServerMsg | YDocUpdateServerMsg | CommentsEventServerMsg;
type CommentsEventServerMsg = ThreadCreatedEvent | ThreadDeletedEvent | ThreadMetadataUpdatedEvent | ThreadUpdatedEvent | CommentCreatedEvent | CommentEditedEvent | CommentDeletedEvent | CommentReactionAdded | CommentReactionRemoved;
type ThreadCreatedEvent = {
    type: ServerMsgCode.THREAD_CREATED;
    threadId: string;
};
type ThreadDeletedEvent = {
    type: ServerMsgCode.THREAD_DELETED;
    threadId: string;
};
type ThreadMetadataUpdatedEvent = {
    type: ServerMsgCode.THREAD_METADATA_UPDATED;
    threadId: string;
};
type ThreadUpdatedEvent = {
    type: ServerMsgCode.THREAD_UPDATED;
    threadId: string;
};
type CommentCreatedEvent = {
    type: ServerMsgCode.COMMENT_CREATED;
    threadId: string;
    commentId: string;
};
type CommentEditedEvent = {
    type: ServerMsgCode.COMMENT_EDITED;
    threadId: string;
    commentId: string;
};
type CommentDeletedEvent = {
    type: ServerMsgCode.COMMENT_DELETED;
    threadId: string;
    commentId: string;
};
type CommentReactionAdded = {
    type: ServerMsgCode.COMMENT_REACTION_ADDED;
    threadId: string;
    commentId: string;
    emoji: string;
};
type CommentReactionRemoved = {
    type: ServerMsgCode.COMMENT_REACTION_REMOVED;
    threadId: string;
    commentId: string;
    emoji: string;
};
/**
 * Sent by the WebSocket server and broadcasted to all clients to announce that
 * a User updated their presence. For example, when a user moves their cursor.
 *
 * In most cases, the data payload will only include the fields from the
 * Presence that have been changed since the last announcement. However, after
 * a new user joins a room, a "full presence" will be announced so the newly
 * connected user will get each other's user full presence at least once. In
 * those cases, the `targetActor` field indicates the newly connected client,
 * so all other existing clients can ignore this broadcasted message.
 */
type UpdatePresenceServerMsg<P extends JsonObject> = {
    readonly type: ServerMsgCode.UPDATE_PRESENCE;
    /**
     * The User whose Presence has changed.
     */
    readonly actor: number;
    /**
     * When set, signifies that this is a Full Presence™ update, not a patch.
     *
     * The numeric value itself no longer has specific meaning. Historically,
     * this field was intended so that clients could ignore these broadcasted
     * full presence messages, but it turned out that getting a full presence
     * "keyframe" from time to time was useful.
     *
     * So nowadays, the presence (pun intended) of this `targetActor` field
     * is a backward-compatible way of expressing that the `data` contains
     * all presence fields, and isn't a partial "patch".
     */
    readonly targetActor: number;
    /**
     * The partial or full Presence of a User. If the `targetActor` field is set,
     * this will be the full Presence, otherwise it only contain the fields that
     * have changed since the last broadcast.
     */
    readonly data: P;
} | {
    readonly type: ServerMsgCode.UPDATE_PRESENCE;
    /**
     * The User whose Presence has changed.
     */
    readonly actor: number;
    /**
     * Not set for partial presence updates.
     */
    readonly targetActor?: undefined;
    /**
     * A partial Presence patch to apply to the User. It will only contain the
     * fields that have changed since the last broadcast.
     */
    readonly data: Partial<P>;
};
/**
 * Sent by the WebSocket server and broadcasted to all clients to announce that
 * a new User has joined the Room.
 */
type UserJoinServerMsg<U extends BaseUserMeta> = {
    readonly type: ServerMsgCode.USER_JOINED;
    readonly actor: number;
    /**
     * The id of the User that has been set in the authentication endpoint.
     * Useful to get additional information about the connected user.
     */
    readonly id: U["id"];
    /**
     * Additional user information that has been set in the authentication
     * endpoint.
     */
    readonly info: U["info"];
    /**
     * Informs the client what (public) permissions this (other) User has.
     */
    readonly scopes: string[];
};
/**
 * Sent by the WebSocket server and broadcasted to all clients to announce that
 * a new User has left the Room.
 */
type UserLeftServerMsg = {
    readonly type: ServerMsgCode.USER_LEFT;
    readonly actor: number;
};
/**
 * Sent by the WebSocket server when the ydoc is updated or when requested based on stateVector passed.
 * Contains a base64 encoded update
 */
type YDocUpdateServerMsg = {
    readonly type: ServerMsgCode.UPDATE_YDOC;
    readonly update: string;
    readonly isSync: boolean;
    readonly stateVector: string | null;
    readonly guid?: string;
    readonly v2?: boolean;
};
/**
 * Sent by the WebSocket server and broadcasted to all clients to announce that
 * a User broadcasted an Event to everyone in the Room.
 */
type BroadcastedEventServerMsg<E extends Json> = {
    readonly type: ServerMsgCode.BROADCASTED_EVENT;
    /**
     * The User who broadcast the Event. Absent when this event is broadcast from
     * the REST API in the backend.
     */
    readonly actor: number;
    /**
     * The arbitrary payload of the Event. This can be any JSON value. Clients
     * will have to manually verify/decode this event.
     */
    readonly event: E;
};
/**
 * Sent by the WebSocket server to a single client in response to the client
 * joining the Room, to provide the initial state of the Room. The payload
 * includes a list of all other Users that already are in the Room.
 */
type RoomStateServerMsg<U extends BaseUserMeta> = {
    readonly type: ServerMsgCode.ROOM_STATE;
    /**
     * Informs the client what their actor ID is going to be.
     * @since v1.2 (WS API v7)
     */
    readonly actor: number;
    /**
     * Secure nonce for the current session.
     * @since v1.2 (WS API v7)
     */
    readonly nonce: string;
    /**
     * Informs the client what permissions the current User (self) has.
     * @since v1.2 (WS API v7)
     */
    readonly scopes: string[];
    readonly users: {
        readonly [otherActor: number]: U & {
            scopes: string[];
        };
    };
};
/**
 * Sent by the WebSocket server to a single client in response to the client
 * joining the Room, to provide the initial Storage state of the Room. The
 * payload includes the entire Storage document.
 */
type InitialDocumentStateServerMsg = {
    readonly type: ServerMsgCode.INITIAL_STORAGE_STATE;
    readonly items: IdTuple<SerializedCrdt>[];
};
/**
 * Sent by the WebSocket server and broadcasted to all clients to announce that
 * a change occurred in the Storage document.
 *
 * The payload of this message contains a list of Ops (aka incremental
 * mutations to make to the initially loaded document).
 */
type UpdateStorageServerMsg = {
    readonly type: ServerMsgCode.UPDATE_STORAGE;
    readonly ops: Op[];
};
/**
 * Sent by the WebSocket server to the client to indicate that certain opIds
 * have been received but were rejected because they caused mutations that are
 * incompatible with the Room's schema.
 */
type RejectedStorageOpServerMsg = {
    readonly type: ServerMsgCode.REJECT_STORAGE_OP;
    readonly opIds: string[];
    readonly reason: string;
};

type HistoryVersion = {
    type: "historyVersion";
    kind: "yjs";
    createdAt: Date;
    id: string;
    authors: {
        id: string;
    }[];
};

type JsonTreeNode = {
    readonly type: "Json";
    readonly id: string;
    readonly key: string;
    readonly payload: Json;
};
type LiveTreeNode<TName extends `Live${string}` = `Live${string}`> = {
    readonly type: TName;
    readonly id: string;
    readonly key: string;
    readonly payload: LsonTreeNode[];
};
type LsonTreeNode = LiveTreeNode | JsonTreeNode;
type UserTreeNode = {
    readonly type: "User";
    readonly id: string;
    readonly key: string;
    readonly payload: {
        readonly connectionId: number;
        readonly id?: string;
        readonly info?: Json;
        readonly presence: JsonObject;
        readonly isReadOnly: boolean;
    };
};
type CustomEventTreeNode = {
    readonly type: "CustomEvent";
    readonly id: string;
    readonly key: string;
    readonly connectionId: number;
    readonly payload: Json;
};
type TreeNode = LsonTreeNode | UserTreeNode | CustomEventTreeNode;

type DevToolsTreeNode_CustomEventTreeNode = CustomEventTreeNode;
type DevToolsTreeNode_JsonTreeNode = JsonTreeNode;
type DevToolsTreeNode_LiveTreeNode<TName extends `Live${string}` = `Live${string}`> = LiveTreeNode<TName>;
type DevToolsTreeNode_LsonTreeNode = LsonTreeNode;
type DevToolsTreeNode_TreeNode = TreeNode;
type DevToolsTreeNode_UserTreeNode = UserTreeNode;
declare namespace DevToolsTreeNode {
  export type { DevToolsTreeNode_CustomEventTreeNode as CustomEventTreeNode, DevToolsTreeNode_JsonTreeNode as JsonTreeNode, DevToolsTreeNode_LiveTreeNode as LiveTreeNode, DevToolsTreeNode_LsonTreeNode as LsonTreeNode, DevToolsTreeNode_TreeNode as TreeNode, DevToolsTreeNode_UserTreeNode as UserTreeNode };
}

type LegacyOthersEvent<P extends JsonObject, U extends BaseUserMeta> = {
    type: "leave";
    user: User<P, U>;
} | {
    type: "enter";
    user: User<P, U>;
} | {
    type: "update";
    user: User<P, U>;
    updates: Partial<P>;
} | {
    type: "reset";
};
type LegacyOthersEventCallback<P extends JsonObject, U extends BaseUserMeta> = (others: readonly User<P, U>[], event: LegacyOthersEvent<P, U>) => void;
type RoomEventMessage<P extends JsonObject, U extends BaseUserMeta, E extends Json> = {
    /**
     * The connection ID of the client that sent the event.
     * If this message was broadcast from the server (via the REST API), then
     * this value will be -1.
     */
    connectionId: number;
    /**
     * The User (from the others list) that sent the event.
     * If this message was broadcast from the server (via the REST API), then
     * this value will be null.
     */
    user: User<P, U> | null;
    event: E;
};
type StorageStatus = "not-loaded" | "loading" | "synchronizing" | "synchronized";
interface History {
    /**
     * Undoes the last operation executed by the current client.
     * It does not impact operations made by other clients.
     *
     * @example
     * room.updatePresence({ selectedId: "xx" }, { addToHistory: true });
     * room.updatePresence({ selectedId: "yy" }, { addToHistory: true });
     * room.history.undo();
     * // room.getPresence() equals { selectedId: "xx" }
     */
    undo: () => void;
    /**
     * Redoes the last operation executed by the current client.
     * It does not impact operations made by other clients.
     *
     * @example
     * room.updatePresence({ selectedId: "xx" }, { addToHistory: true });
     * room.updatePresence({ selectedId: "yy" }, { addToHistory: true });
     * room.history.undo();
     * // room.getPresence() equals { selectedId: "xx" }
     * room.history.redo();
     * // room.getPresence() equals { selectedId: "yy" }
     */
    redo: () => void;
    /**
     * Returns whether there are any operations to undo.
     *
     * @example
     * room.updatePresence({ selectedId: "xx" }, { addToHistory: true });
     * // room.history.canUndo() is true
     * room.history.undo();
     * // room.history.canUndo() is false
     */
    canUndo: () => boolean;
    /**
     * Returns whether there are any operations to redo.
     *
     * @example
     * room.updatePresence({ selectedId: "xx" }, { addToHistory: true });
     * room.history.undo();
     * // room.history.canRedo() is true
     * room.history.redo();
     * // room.history.canRedo() is false
     */
    canRedo: () => boolean;
    /**
     * Clears the undo and redo stacks. This operation cannot be undone ;)
     */
    clear: () => void;
    /**
     * All future modifications made on the Room will be merged together to create a single history item until resume is called.
     *
     * @example
     * room.updatePresence({ cursor: { x: 0, y: 0 } }, { addToHistory: true });
     * room.history.pause();
     * room.updatePresence({ cursor: { x: 1, y: 1 } }, { addToHistory: true });
     * room.updatePresence({ cursor: { x: 2, y: 2 } }, { addToHistory: true });
     * room.history.resume();
     * room.history.undo();
     * // room.getPresence() equals { cursor: { x: 0, y: 0 } }
     */
    pause: () => void;
    /**
     * Resumes history. Modifications made on the Room are not merged into a single history item anymore.
     *
     * @example
     * room.updatePresence({ cursor: { x: 0, y: 0 } }, { addToHistory: true });
     * room.history.pause();
     * room.updatePresence({ cursor: { x: 1, y: 1 } }, { addToHistory: true });
     * room.updatePresence({ cursor: { x: 2, y: 2 } }, { addToHistory: true });
     * room.history.resume();
     * room.history.undo();
     * // room.getPresence() equals { cursor: { x: 0, y: 0 } }
     */
    resume: () => void;
}
type HistoryEvent = {
    canUndo: boolean;
    canRedo: boolean;
};
type BroadcastOptions = {
    /**
     * Whether or not event is queued if the connection is currently closed.
     *
     * ❗ We are not sure if we want to support this option in the future so it might be deprecated to be replaced by something else
     */
    shouldQueueEventIfNotReady: boolean;
};
type SubscribeFn<P extends JsonObject, _TStorage extends LsonObject, U extends BaseUserMeta, E extends Json> = {
    /**
     * Subscribe to the current user presence updates.
     *
     * @param listener the callback that is called every time the current user presence is updated with {@link Room.updatePresence}.
     *
     * @returns Unsubscribe function.
     *
     * @example
     * room.subscribe("my-presence", (presence) => {
     *   // Do something
     * });
     */
    (type: "my-presence", listener: Callback<P>): () => void;
    /**
     * Subscribe to the other users updates.
     *
     * @param listener the callback that is called when a user enters or leaves the room or when a user update its presence.
     *
     * @returns Unsubscribe function.
     *
     * @example
     * room.subscribe("others", (others) => {
     *   // Do something
     * });
     *
     */
    (type: "others", listener: LegacyOthersEventCallback<P, U>): () => void;
    /**
     * Subscribe to events broadcasted by {@link Room.broadcastEvent}
     *
     * @param listener the callback that is called when a user calls {@link Room.broadcastEvent}
     *
     * @returns Unsubscribe function.
     *
     * @example
     * room.subscribe("event", ({ event, connectionId }) => {
     *   // Do something
     * });
     *
     */
    (type: "event", listener: Callback<RoomEventMessage<P, U, E>>): () => void;
    /**
     * Subscribe to errors thrown in the room.
     *
     * @returns Unsubscribe function.
     *
     */
    (type: "error", listener: Callback<LiveblocksError>): () => void;
    /**
     * Subscribe to connection status updates. The callback will be called any
     * time the status changes.
     *
     * @returns Unsubscribe function.
     *
     */
    (type: "status", listener: Callback<Status>): () => void;
    /**
     * Subscribe to the exceptional event where reconnecting to the Liveblocks
     * servers is taking longer than usual. This typically is a sign of a client
     * that has lost internet connectivity.
     *
     * This isn't problematic (because the Liveblocks client is still trying to
     * reconnect), but it's typically a good idea to inform users about it if
     * the connection takes too long to recover.
     */
    (type: "lost-connection", listener: Callback<LostConnectionEvent>): () => void;
    /**
     * Subscribes to changes made on a Live structure. Returns an unsubscribe function.
     *
     * @param callback The callback this called when the Live structure changes.
     *
     * @returns Unsubscribe function.
     *
     * @example
     * const liveMap = new LiveMap();  // Could also be LiveList or LiveObject
     * const unsubscribe = room.subscribe(liveMap, (liveMap) => { });
     * unsubscribe();
     */
    <L extends LiveStructure>(liveStructure: L, callback: (node: L) => void): () => void;
    /**
     * Subscribes to changes made on a Live structure and all the nested data
     * structures. Returns an unsubscribe function. In a future version, we
     * will also expose what exactly changed in the Live structure.
     *
     * @param callback The callback this called when the Live structure, or any
     * of its nested values, changes.
     *
     * @returns Unsubscribe function.
     *
     * @example
     * const liveMap = new LiveMap();  // Could also be LiveList or LiveObject
     * const unsubscribe = room.subscribe(liveMap, (updates) => { }, { isDeep: true });
     * unsubscribe();
     */
    <L extends LiveStructure>(liveStructure: L, callback: StorageCallback, options: {
        isDeep: true;
    }): () => void;
    /**
     * Subscribe to the current user's history changes.
     *
     * @returns Unsubscribe function.
     *
     * @example
     * room.subscribe("history", ({ canUndo, canRedo }) => {
     *   // Do something
     * });
     */
    (type: "history", listener: Callback<HistoryEvent>): () => void;
    /**
     * Subscribe to storage status changes.
     *
     * @returns Unsubscribe function.
     *
     * @example
     * room.subscribe("storage-status", (status) => {
     *   switch(status) {
     *      case "not-loaded":
     *        break;
     *      case "loading":
     *        break;
     *      case "synchronizing":
     *        break;
     *      case "synchronized":
     *        break;
     *      default:
     *        break;
     *   }
     * });
     */
    (type: "storage-status", listener: Callback<StorageStatus>): () => void;
    (type: "comments", listener: Callback<CommentsEventServerMsg>): () => void;
};
type GetThreadsOptions<M extends BaseMetadata> = {
    cursor?: string;
    query?: {
        resolved?: boolean;
        metadata?: Partial<QueryMetadata<M>>;
    };
};
type GetThreadsSinceOptions = {
    since: Date;
    signal?: AbortSignal;
};
type UploadAttachmentOptions = {
    signal?: AbortSignal;
};
type ListTextVersionsSinceOptions = {
    since: Date;
    signal?: AbortSignal;
};
type GetSubscriptionSettingsOptions = {
    signal?: AbortSignal;
};
/**
 * @private Widest-possible Room type, matching _any_ Room instance. Note that
 * this type is different from `Room`-without-type-arguments. That represents
 * a Room instance using globally augmented types only, which is narrower.
 */
type OpaqueRoom = Room<JsonObject, LsonObject, BaseUserMeta, Json, BaseMetadata>;
type Room<P extends JsonObject = DP, S extends LsonObject = DS, U extends BaseUserMeta = DU, E extends Json = DE, M extends BaseMetadata = DM> = {
    /**
     * @private
     *
     * Private methods and variables used in the core internals, but as a user
     * of Liveblocks, NEVER USE ANY OF THESE DIRECTLY, because bad things
     * will probably happen if you do.
     */
    readonly [kInternal]: PrivateRoomApi;
    /**
     * The id of the room.
     */
    readonly id: string;
    /**
     * Return the current connection status for this room. Can be used to display
     * a status badge for your Liveblocks connection.
     */
    getStatus(): Status;
    readonly subscribe: SubscribeFn<P, S, U, E>;
    /**
     * Room's history contains functions that let you undo and redo operation made on by the current client on the presence and storage.
     */
    readonly history: History;
    /**
     * Gets the current user.
     * Returns null if not it is not yet connected to the room.
     *
     * @example
     * const user = room.getSelf();
     */
    getSelf(): User<P, U> | null;
    /**
     * Gets the presence of the current user.
     *
     * @example
     * const presence = room.getPresence();
     */
    getPresence(): P;
    /**
     * Gets all the other users in the room.
     *
     * @example
     * const others = room.getOthers();
     */
    getOthers(): readonly User<P, U>[];
    /**
     * Updates the presence of the current user. Only pass the properties you want to update. No need to send the full presence.
     * @param patch A partial object that contains the properties you want to update.
     * @param options Optional object to configure the behavior of updatePresence.
     *
     * @example
     * room.updatePresence({ x: 0 });
     * room.updatePresence({ y: 0 });
     *
     * const presence = room.getPresence();
     * // presence is equivalent to { x: 0, y: 0 }
     */
    updatePresence(patch: Partial<P>, options?: {
        /**
         * Whether or not the presence should have an impact on the undo/redo history.
         */
        addToHistory: boolean;
    }): void;
    /**
     * Sends Yjs document updates to Liveblocks server.
     *
     * @param {string} data the doc update to send to the server, base64 encoded uint8array
     */
    updateYDoc(data: string, guid?: string, isV2?: boolean): void;
    /**
     * Sends a request for the current document from liveblocks server
     */
    fetchYDoc(stateVector: string, guid?: string, isV2?: boolean): void;
    /**
     * Broadcasts an event to other users in the room. Event broadcasted to the room can be listened with {@link Room.subscribe}("event").
     * @param {any} event the event to broadcast. Should be serializable to JSON
     *
     * @example
     * // On client A
     * room.broadcastEvent({ type: "EMOJI", emoji: "🔥" });
     *
     * // On client B
     * room.subscribe("event", ({ event }) => {
     *   if(event.type === "EMOJI") {
     *     // Do something
     *   }
     * });
     */
    broadcastEvent(event: E, options?: BroadcastOptions): void;
    /**
     * Get the room's storage asynchronously.
     * The storage's root is a {@link LiveObject}.
     *
     * @example
     * const { root } = await room.getStorage();
     */
    getStorage(): Promise<{
        root: LiveObject<S>;
    }>;
    /**
     * Get the room's storage synchronously.
     * The storage's root is a {@link LiveObject}.
     *
     * @example
     * const root = room.getStorageSnapshot();
     */
    getStorageSnapshot(): LiveObject<S> | null;
    /**
     * All possible room events, subscribable from a single place.
     *
     * @private These event sources are private for now, but will become public
     * once they're stable.
     */
    readonly events: {
        readonly status: Observable<Status>;
        readonly lostConnection: Observable<LostConnectionEvent>;
        readonly customEvent: Observable<RoomEventMessage<P, U, E>>;
        readonly self: Observable<User<P, U>>;
        readonly myPresence: Observable<P>;
        readonly others: Observable<OthersEvent<P, U>>;
        readonly storageBatch: Observable<StorageUpdate[]>;
        readonly history: Observable<HistoryEvent>;
        /**
         * Subscribe to the storage loaded event. Will fire any time a full Storage
         * copy is downloaded. (This happens after the initial connect, and on
         * every reconnect.)
         */
        readonly storageDidLoad: Observable<void>;
        readonly storageStatus: Observable<StorageStatus>;
        readonly ydoc: Observable<YDocUpdateServerMsg | UpdateYDocClientMsg>;
        readonly comments: Observable<CommentsEventServerMsg>;
        /**
         * Called right before the room is destroyed. The event cannot be used to
         * prevent the room from being destroyed, only to be informed that this is
         * imminent.
         */
        readonly roomWillDestroy: Observable<void>;
    };
    /**
     * Batches modifications made during the given function.
     * All the modifications are sent to other clients in a single message.
     * All the subscribers are called only after the batch is over.
     * All the modifications are merged in a single history item (undo/redo).
     *
     * @example
     * const { root } = await room.getStorage();
     * room.batch(() => {
     *   root.set("x", 0);
     *   room.updatePresence({ cursor: { x: 100, y: 100 }});
     * });
     */
    batch<T>(fn: () => T): T;
    /**
     * Get the storage status.
     *
     * - `not-loaded`: Initial state when entering the room.
     * - `loading`: Once the storage has been requested via room.getStorage().
     * - `synchronizing`: When some local updates have not been acknowledged by Liveblocks servers.
     * - `synchronized`: Storage is in sync with Liveblocks servers.
     */
    getStorageStatus(): StorageStatus;
    isPresenceReady(): boolean;
    isStorageReady(): boolean;
    /**
     * Returns a Promise that resolves as soon as Presence is available, which
     * happens shortly after the WebSocket connection has been established. Once
     * this happens, `self` and `others` are known and available to use. After
     * awaiting this promise, `.isPresenceReady()` will be guaranteed to be true.
     * Even when calling this function multiple times, it's guaranteed to return
     * the same Promise instance.
     */
    waitUntilPresenceReady(): Promise<void>;
    /**
     * Returns a Promise that resolves as soon as Storage has been loaded and
     * available. After awaiting this promise, `.isStorageReady()` will be
     * guaranteed to be true. Even when calling this function multiple times,
     * it's guaranteed to return the same Promise instance.
     */
    waitUntilStorageReady(): Promise<void>;
    /**
     * Start an attempt to connect the room (aka "enter" it). Calling
     * `.connect()` only has an effect if the room is still in its idle initial
     * state, or the room was explicitly disconnected, or reconnection attempts
     * were stopped (for example, because the user isn't authorized to enter the
     * room). Will be a no-op otherwise.
     */
    connect(): void;
    /**
     * Disconnect the room's connection to the Liveblocks server, if any. Puts
     * the room back into an idle state. It will not do anything until either
     * `.connect()` or `.reconnect()` is called.
     *
     * Only use this API if you wish to connect the room again at a later time.
     * If you want to disconnect the room because you no longer need it, call
     * `.destroy()` instead.
     */
    disconnect(): void;
    /**
     * Reconnect the room to the Liveblocks server by re-establishing a fresh
     * connection. If the room is not connected yet, initiate it.
     */
    reconnect(): void;
    /**
     * Returns the threads within the current room and their associated inbox notifications.
     * It also returns the request date that can be used for subsequent polling.
     *
     * @example
     * const {
     *   threads,
     *   inboxNotifications,
     *   subscriptions,
     *   requestedAt
     * } = await room.getThreads({ query: { resolved: false }});
     */
    getThreads(options?: GetThreadsOptions<M>): Promise<{
        threads: ThreadData<M>[];
        inboxNotifications: InboxNotificationData[];
        subscriptions: SubscriptionData[];
        requestedAt: Date;
        nextCursor: string | null;
        permissionHints: Record<string, Permission[]>;
    }>;
    /**
     * Returns the updated and deleted threads and their associated inbox notifications and subscriptions since the requested date.
     *
     * @example
     * const result = await room.getThreads();
     * // ... //
     * await room.getThreadsSince({ since: result.requestedAt });
     */
    getThreadsSince(options: GetThreadsSinceOptions): Promise<{
        threads: {
            updated: ThreadData<M>[];
            deleted: ThreadDeleteInfo[];
        };
        inboxNotifications: {
            updated: InboxNotificationData[];
            deleted: InboxNotificationDeleteInfo[];
        };
        subscriptions: {
            updated: SubscriptionData[];
            deleted: SubscriptionDeleteInfo[];
        };
        requestedAt: Date;
        permissionHints: Record<string, Permission[]>;
    }>;
    /**
     * Returns a thread and the associated inbox notification and subscription if it exists.
     *
     * @example
     * const { thread, inboxNotification, subscription } = await room.getThread("th_xxx");
     */
    getThread(threadId: string): Promise<{
        thread?: ThreadData<M>;
        inboxNotification?: InboxNotificationData;
        subscription?: SubscriptionData;
    }>;
    /**
     * Creates a thread.
     *
     * @example
     * const thread = await room.createThread({
     *   body: {
     *     version: 1,
     *     content: [{ type: "paragraph", children: [{ text: "Hello" }] }],
     *   },
     * })
     */
    createThread(options: {
        threadId?: string;
        commentId?: string;
        metadata: M | undefined;
        body: CommentBody;
        attachmentIds?: string[];
    }): Promise<ThreadData<M>>;
    /**
     * Deletes a thread.
     *
     * @example
     * await room.deleteThread("th_xxx");
     */
    deleteThread(threadId: string): Promise<void>;
    /**
     * Edits a thread's metadata.
     * To delete an existing metadata property, set its value to `null`.
     *
     * @example
     * await room.editThreadMetadata({ threadId: "th_xxx", metadata: { x: 100, y: 100 } })
     */
    editThreadMetadata(options: {
        metadata: Patchable<M>;
        threadId: string;
    }): Promise<M>;
    /**
     * Marks a thread as resolved.
     *
     * @example
     * await room.markThreadAsResolved("th_xxx");
     */
    markThreadAsResolved(threadId: string): Promise<void>;
    /**
     * Marks a thread as unresolved.
     *
     * @example
     * await room.markThreadAsUnresolved("th_xxx");
     */
    markThreadAsUnresolved(threadId: string): Promise<void>;
    /**
     * Subscribes the user to a thread.
     *
     * @example
     * await room.subscribeToThread("th_xxx");
     */
    subscribeToThread(threadId: string): Promise<SubscriptionData>;
    /**
     * Unsubscribes the user from a thread.
     *
     * @example
     * await room.unsubscribeFromThread("th_xxx");
     */
    unsubscribeFromThread(threadId: string): Promise<void>;
    /**
     * Creates a comment.
     *
     * @example
     * await room.createComment({
     *   threadId: "th_xxx",
     *   body: {
     *     version: 1,
     *     content: [{ type: "paragraph", children: [{ text: "Hello" }] }],
     *   },
     * });
     */
    createComment(options: {
        threadId: string;
        commentId?: string;
        body: CommentBody;
        attachmentIds?: string[];
    }): Promise<CommentData>;
    /**
     * Edits a comment.
     *
     * @example
     * await room.editComment({
     *   threadId: "th_xxx",
     *   commentId: "cm_xxx"
     *   body: {
     *     version: 1,
     *     content: [{ type: "paragraph", children: [{ text: "Hello" }] }],
     *   },
     * });
     */
    editComment(options: {
        threadId: string;
        commentId: string;
        body: CommentBody;
        attachmentIds?: string[];
    }): Promise<CommentData>;
    /**
     * Deletes a comment.
     * If it is the last non-deleted comment, the thread also gets deleted.
     *
     * @example
     * await room.deleteComment({
     *   threadId: "th_xxx",
     *   commentId: "cm_xxx"
     * });
     */
    deleteComment(options: {
        threadId: string;
        commentId: string;
    }): Promise<void>;
    /**
     * Adds a reaction from a comment for the current user.
     *
     * @example
     * await room.addReaction({ threadId: "th_xxx", commentId: "cm_xxx", emoji: "👍" })
     */
    addReaction(options: {
        threadId: string;
        commentId: string;
        emoji: string;
    }): Promise<CommentUserReaction>;
    /**
     * Removes a reaction from a comment.
     *
     * @example
     * await room.removeReaction({ threadId: "th_xxx", commentId: "cm_xxx", emoji: "👍" })
     */
    removeReaction(options: {
        threadId: string;
        commentId: string;
        emoji: string;
    }): Promise<void>;
    /**
     * Creates a local attachment from a file.
     *
     * @example
     * room.prepareAttachment(file);
     */
    prepareAttachment(file: File): CommentLocalAttachment;
    /**
     * Uploads a local attachment.
     *
     * @example
     * const attachment = room.prepareAttachment(file);
     * await room.uploadAttachment(attachment);
     */
    uploadAttachment(attachment: CommentLocalAttachment, options?: UploadAttachmentOptions): Promise<CommentAttachment>;
    /**
     * Returns a presigned URL for an attachment by its ID.
     *
     * @example
     * await room.getAttachmentUrl("at_xxx");
     */
    getAttachmentUrl(attachmentId: string): Promise<string>;
    /**
     * Gets the user's subscription settings for the current room.
     *
     * @example
     * const settings = await room.getSubscriptionSettings();
     */
    getSubscriptionSettings(options?: GetSubscriptionSettingsOptions): Promise<RoomSubscriptionSettings>;
    /**
     * Updates the user's subscription settings for the current room.
     *
     * @example
     * await room.updateSubscriptionSettings({ threads: "replies_and_mentions" });
     */
    updateSubscriptionSettings(settings: Partial<RoomSubscriptionSettings>): Promise<RoomSubscriptionSettings>;
    /**
     * @private
     *
     * Internal use only. Signature might change in the future.
     */
    markInboxNotificationAsRead(notificationId: string): Promise<void>;
};
type YjsSyncStatus = "loading" | "synchronizing" | "synchronized";
/**
 * Interface that @liveblocks/yjs must respect.
 * This interface type is declare in @liveblocks/core, so we don't have to
 * depend on `yjs`. It's only used to determine the API contract between
 * @liveblocks/core and @liveblocks/yjs.
 */
interface IYjsProvider {
    synced: boolean;
    getStatus: () => YjsSyncStatus;
    on(event: "sync", listener: (synced: boolean) => void): void;
    on(event: "status", listener: (status: YjsSyncStatus) => void): void;
    off(event: "sync", listener: (synced: boolean) => void): void;
    off(event: "status", listener: (status: YjsSyncStatus) => void): void;
}
/**
 * A "Sync Source" can be a Storage document, a Yjs document, Comments,
 * Notifications, etc.
 * The Client keeps a registry of all active sync sources, and will use it to
 * determine the global "sync status" for Liveblocks.
 */
interface SyncSource {
    setSyncStatus(status: InternalSyncStatus): void;
    destroy(): void;
}
/**
 * @private
 *
 * Private methods to directly control the underlying state machine for this
 * room. Used in the core internals and for unit testing, but as a user of
 * Liveblocks, NEVER USE ANY OF THESE METHODS DIRECTLY, because bad things
 * will probably happen if you do.
 */
type PrivateRoomApi = {
    presenceBuffer: Json | undefined;
    undoStack: readonly (readonly Readonly<HistoryOp<JsonObject>>[])[];
    nodeCount: number;
    getYjsProvider(): IYjsProvider | undefined;
    setYjsProvider(provider: IYjsProvider | undefined): void;
    yjsProviderDidChange: Observable<void>;
    getSelf_forDevTools(): UserTreeNode | null;
    getOthers_forDevTools(): readonly UserTreeNode[];
    reportTextEditor(editor: TextEditorType, rootKey: string): Promise<void>;
    createTextMention(userId: string, mentionId: string): Promise<void>;
    deleteTextMention(mentionId: string): Promise<void>;
    listTextVersions(): Promise<{
        versions: HistoryVersion[];
        requestedAt: Date;
    }>;
    listTextVersionsSince(options: ListTextVersionsSinceOptions): Promise<{
        versions: HistoryVersion[];
        requestedAt: Date;
    }>;
    getTextVersion(versionId: string): Promise<Response>;
    createTextVersion(): Promise<void>;
    executeContextualPrompt(options: {
        prompt: string;
        context: ContextualPromptContext;
        previous?: {
            prompt: string;
            response: ContextualPromptResponse;
        };
        signal: AbortSignal;
    }): Promise<string>;
    simulate: {
        explicitClose(event: IWebSocketCloseEvent): void;
        rawSend(data: string): void;
    };
    attachmentUrlsStore: BatchStore<string, string>;
};
type HistoryOp<P extends JsonObject> = Op | {
    readonly type: "presence";
    readonly data: P;
};
type StaticSessionInfo = {
    readonly userId?: string;
    readonly userInfo?: IUserInfo;
};
type DynamicSessionInfo = {
    readonly actor: number;
    readonly nonce: string;
    readonly scopes: string[];
};
type Polyfills = {
    atob?: (data: string) => string;
    fetch?: typeof fetch;
    WebSocket?: IWebSocket;
};
/**
 * Makes all tuple positions optional.
 * Example, turns:
 *   [foo: string; bar: number]
 * into:
 *   [foo?: string; bar?: number]
 */
type OptionalTuple<T extends any[]> = {
    [K in keyof T]?: T[K];
};
/**
 * Returns Partial<T> if all fields on C are optional, T otherwise.
 */
type PartialUnless<C, T> = Record<string, never> extends C ? Partial<T> : [
    C
] extends [never] ? Partial<T> : T;
/**
 * Returns OptionalTupleUnless<T> if all fields on C are optional, T otherwise.
 */
type OptionalTupleUnless<C, T extends any[]> = Record<string, never> extends C ? OptionalTuple<T> : [
    C
] extends [never] ? OptionalTuple<T> : T;
type LargeMessageStrategy = "default" | "split" | "experimental-fallback-to-http";

declare const brand: unique symbol;
type Brand<T, TBrand extends string> = T & {
    [brand]: TBrand;
};
type DistributiveOmit<T, K extends PropertyKey> = T extends any ? Omit<T, K> : never;
/**
 * Throw an error, but as an expression instead of a statement.
 */
declare function raise(msg: string): never;
/**
 * Drop-in replacement for Object.entries() that retains better types.
 */
declare function entries<O extends {
    [key: string]: unknown;
}, K extends keyof O>(obj: O): [K, O[K]][];
/**
 * Drop-in replacement for Object.keys() that retains better types.
 */
declare function keys<O extends {
    [key: string]: unknown;
}, K extends keyof O>(obj: O): K[];
/**
 * Creates a new object by mapping a function over all values. Keys remain the
 * same. Think Array.prototype.map(), but for values in an object.
 */
declare function mapValues<V, O extends Record<string, unknown>>(obj: O, mapFn: (value: O[keyof O], key: keyof O) => V): {
    [K in keyof O]: V;
};
/**
 * Alternative to JSON.parse() that will not throw in production. If the passed
 * string cannot be parsed, this will return `undefined`.
 */
declare function tryParseJson(rawMessage: string): Json | undefined;
/**
 * Decode base64 string.
 */
declare function b64decode(b64value: string): string;
type RemoveUndefinedValues<T> = {
    [K in keyof T]-?: Exclude<T[K], undefined>;
};
/**
 * Returns a new object instance where all explictly-undefined values are
 * removed.
 */
declare function compactObject<O extends Record<string, unknown>>(obj: O): RemoveUndefinedValues<O>;
/**
 * Returns a promise that resolves after the given number of milliseconds.
 */
declare function wait(millis: number): Promise<void>;
/**
 * Returns whatever the given promise returns, but will be rejected with
 * a "Timed out" error if the given promise does not return or reject within
 * the given timeout period (in milliseconds).
 */
declare function withTimeout<T>(promise: Promise<T>, millis: number, errmsg: string): Promise<T>;
/**
 * Memoize a promise factory, so that each subsequent call will return the same
 * pending or success promise. If the promise rejects, will retain that failed
 * promise for a small time period, after which the next attempt will reset the
 * memoized value.
 */
declare function memoizeOnSuccess<T>(factoryFn: () => Promise<T>): () => Promise<T>;

type Cursor = Brand<string, "Cursor">;
type ISODateString = Brand<string, "ISODateString">;
type ChatId = string;
type MessageId = Brand<`ms_${string}`, "MessageId">;
type CmdId = Brand<string, "CmdId">;
type CopilotId = Brand<`co_${string}`, "CopilotId">;
type ServerAiMsg = ServerCmdResponse | ServerEvent;
type DefineCmd<CmdName extends string, TRequest, TResponse> = [
    Resolve<{
        cmd: CmdName;
        cmdId: CmdId;
    } & TRequest>,
    Resolve<{
        cmd: CmdName;
        cmdId: CmdId;
    } & TResponse>
];
type CommandPair = GetChatsPair | GetOrCreateChatPair | DeleteChatPair | GetMessageTreePair | DeleteMessagePair | ClearChatPair | AskInChatPair | AbortAiPair | SetToolResultPair;
type ServerCmdResponse<T extends CommandPair = CommandPair> = T[1];
type GetChatsResponse = ServerCmdResponse<GetChatsPair>;
type GetOrCreateChatResponse = ServerCmdResponse<GetOrCreateChatPair>;
type DeleteChatResponse = ServerCmdResponse<DeleteChatPair>;
type GetMessageTreeResponse = ServerCmdResponse<GetMessageTreePair>;
type DeleteMessageResponse = ServerCmdResponse<DeleteMessagePair>;
type ClearChatResponse = ServerCmdResponse<ClearChatPair>;
type AskInChatResponse = ServerCmdResponse<AskInChatPair>;
type AbortAiResponse = ServerCmdResponse<AbortAiPair>;
type GetChatsPair = DefineCmd<"get-chats", {
    cursor?: Cursor;
    pageSize?: number;
}, {
    chats: AiChat[];
    nextCursor: Cursor | null;
}>;
type CreateChatOptions = {
    /** A human-friendly title for the chat. If not set, it will get auto-generated after the first response. */
    title?: string;
    /** Arbitrary metadata to record for this chat. This can be later used to filter the list of chats by metadata. */
    metadata?: Record<string, string | string[]>;
};
type GetOrCreateChatPair = DefineCmd<"get-or-create-chat", {
    id: ChatId;
    options?: CreateChatOptions;
}, {
    chat: AiChat;
}>;
type DeleteChatPair = DefineCmd<"delete-chat", {
    chatId: ChatId;
}, {
    chatId: ChatId;
}>;
type GetMessageTreePair = DefineCmd<"get-message-tree", {
    chatId: ChatId;
}, {
    chat: AiChat;
    messages: AiChatMessage[];
}>;
type DeleteMessagePair = DefineCmd<"delete-message", {
    chatId: ChatId;
    messageId: MessageId;
}, {
    chatId: ChatId;
    messageId: MessageId;
}>;
type ClearChatPair = DefineCmd<"clear-chat", {
    chatId: ChatId;
}, {
    chatId: ChatId;
}>;
type AiGenerationOptions = {
    /**
     * The Copilot ID to use for this request. If not provided, a built-in
     * default Copilot will be used instead of one that you configured via the
     * dashboard.
     */
    copilotId?: CopilotId;
    stream?: boolean;
    tools?: AiToolDescription[];
    knowledge?: AiKnowledgeSource[];
    timeout?: number;
};
type AskInChatPair = DefineCmd<"ask-in-chat", {
    chatId: ChatId;
    /** The chat message to use as the source to create the assistant response. */
    sourceMessage: // An existing message ID to reply to
    MessageId | {
        id: MessageId;
        parentMessageId: MessageId | null;
        content: AiUserContentPart[];
    };
    /**
     * The new (!) message ID to output the assistant response into. This ID
     * should be a non-existing message ID, optimistically assigned by the
     * client. The output message will be created as a child to the source
     * message ID.
     */
    targetMessageId: MessageId;
    generationOptions: AiGenerationOptions;
}, {
    sourceMessage?: AiChatMessage;
    targetMessage: AiChatMessage;
}>;
type AbortAiPair = DefineCmd<"abort-ai", {
    messageId: MessageId;
}, {
    ok: true;
}>;
type ToolResultResponse<R extends JsonObject = JsonObject> = Relax<({
    data: R;
    description?: string;
} | {
    error: string;
} | {
    cancel: true | /* reason */ string;
})>;
type NonEmptyString<T extends string> = T & {
    __nonEmpty: true;
};
type RenderableToolResultResponse<R extends JsonObject = JsonObject> = Relax<{
    type: "success";
    data: R;
} | {
    type: "error";
    error: NonEmptyString<string>;
} | {
    type: "cancelled";
    cancelled: true;
    reason?: string;
}>;
type SetToolResultPair = DefineCmd<"set-tool-result", {
    chatId: ChatId;
    messageId: MessageId;
    invocationId: string;
    result: ToolResultResponse;
    generationOptions: AiGenerationOptions;
}, {
    ok: true;
    message: AiChatMessage;
} | {
    ok: false;
}>;
type ServerEvent = RebootedEvent | CmdFailedEvent | WarningServerEvent | ErrorServerEvent | SyncServerEvent | DeltaServerEvent | SettleServerEvent;
type RebootedEvent = {
    event: "rebooted";
};
type CmdFailedEvent = {
    event: "cmd-failed";
    failedCmd: CommandPair[0]["cmd"];
    failedCmdId: CmdId;
    error: string;
};
type WarningServerEvent = {
    event: "warning";
    message: string;
};
type ErrorServerEvent = {
    event: "error";
    error: string;
};
type SyncServerEvent = {
    event: "sync";
    chats?: AiChat[];
    messages?: AiChatMessage[];
    clear?: ChatId[];
    "-chats"?: ChatId[];
    "-messages"?: Pick<AiChatMessage, "id" | "chatId">[];
};
/**
 * A "delta" event is sent to append an incoming delta chunk to an assistant
 * message.
 */
type DeltaServerEvent = {
    event: "delta";
    id: MessageId;
    delta: AiAssistantDeltaUpdate;
};
/**
 * A "settle" event happens after 0 or more "delta" messages, and signifies the
 * end of a stream of updates to a pending assistant message. This event turns
 * a pending message into either a completed or failed assistant message.
 */
type SettleServerEvent = {
    event: "settle";
    message: AiAwaitingToolAssistantMessage | AiCompletedAssistantMessage | AiFailedAssistantMessage;
};
type AiChat = {
    id: ChatId;
    title: string;
    metadata: Record<string, string | string[]>;
    createdAt: ISODateString;
    lastMessageAt?: ISODateString;
    deletedAt?: ISODateString;
};
type AiToolDescription = {
    name: string;
    description?: string;
    parameters: JSONSchema7;
};
type AiToolInvocationPart<A extends JsonObject = JsonObject, R extends JsonObject = JsonObject> = Relax<AiReceivingToolInvocationPart | AiExecutingToolInvocationPart<A> | AiExecutedToolInvocationPart<A, R>>;
type AiReceivingToolInvocationPart = {
    type: "tool-invocation";
    stage: "receiving";
    invocationId: string;
    name: string;
    partialArgs: Json;
};
type AiExecutingToolInvocationPart<A extends JsonObject = JsonObject> = {
    type: "tool-invocation";
    stage: "executing";
    invocationId: string;
    name: string;
    args: A;
};
type AiExecutedToolInvocationPart<A extends JsonObject = JsonObject, R extends JsonObject = JsonObject> = {
    type: "tool-invocation";
    stage: "executed";
    invocationId: string;
    name: string;
    args: A;
    result: RenderableToolResultResponse<R>;
};
type AiTextPart = {
    type: "text";
    text: string;
};
type AiTextDelta = {
    type: "text-delta";
    textDelta: string;
};
type AiReasoningDelta = Relax<{
    type: "reasoning-delta";
    textDelta: string;
} | {
    type: "reasoning-delta";
    signature: string;
}>;
type AiReasoningPart = {
    type: "reasoning";
    text: string;
};
type AiUploadedImagePart = {
    type: "image";
    id: string;
    name: string;
    size: number;
    mimeType: string;
};
type AiUserContentPart = AiTextPart | AiUploadedImagePart;
type AiAssistantContentPart = AiReasoningPart | AiTextPart | AiToolInvocationPart;
type AiAssistantDeltaUpdate = AiTextDelta | AiReasoningDelta | AiExecutingToolInvocationPart;
type AiUserMessage = {
    id: MessageId;
    chatId: ChatId;
    parentId: MessageId | null;
    role: "user";
    content: AiUserContentPart[];
    createdAt: ISODateString;
    deletedAt?: ISODateString;
};
type AiAssistantMessage = Relax<AiGeneratingAssistantMessage | AiAwaitingToolAssistantMessage | AiCompletedAssistantMessage | AiFailedAssistantMessage>;
type AiGeneratingAssistantMessage = {
    id: MessageId;
    chatId: ChatId;
    parentId: MessageId | null;
    role: "assistant";
    createdAt: ISODateString;
    deletedAt?: ISODateString;
    status: "generating";
    contentSoFar: AiAssistantContentPart[];
};
type AiAwaitingToolAssistantMessage = {
    id: MessageId;
    chatId: ChatId;
    parentId: MessageId | null;
    role: "assistant";
    createdAt: ISODateString;
    deletedAt?: ISODateString;
    status: "awaiting-tool";
    contentSoFar: AiAssistantContentPart[];
};
type AiCompletedAssistantMessage = {
    id: MessageId;
    chatId: ChatId;
    parentId: MessageId | null;
    role: "assistant";
    content: AiAssistantContentPart[];
    createdAt: ISODateString;
    deletedAt?: ISODateString;
    status: "completed";
};
type AiFailedAssistantMessage = {
    id: MessageId;
    chatId: ChatId;
    parentId: MessageId | null;
    role: "assistant";
    createdAt: ISODateString;
    deletedAt?: ISODateString;
    status: "failed";
    contentSoFar: AiAssistantContentPart[];
    errorReason: string;
};
type AiChatMessage = Relax<AiUserMessage | AiAssistantMessage>;
type AiKnowledgeSource = {
    description: string;
    value: Json;
};

type JSONObjectSchema7 = JSONSchema7 & {
    type: "object";
};
type NoFields = {};
type Infer<T> = T extends JSONSchema7 ? InferFromSchema<T> : never;
type InferAllOf<T extends readonly JSONSchema7[]> = T extends readonly [
    infer U,
    ...infer R
] ? R extends readonly JSONSchema7[] ? Infer<U> & InferAllOf<R> : Infer<U> : unknown;
type InferRequireds<P, R extends readonly string[]> = {
    -readonly [K in keyof P as K extends string ? K extends Extract<K, R[number]> ? K : never : never]: Infer<P[K]>;
};
type InferOptionals<P, R extends readonly string[]> = {
    -readonly [K in keyof P as K extends string ? K extends Extract<K, R[number]> ? never : K : never]?: Infer<P[K]>;
};
type InferBaseObject<T extends JSONObjectSchema7> = T extends {
    properties?: infer P extends Record<string, JSONSchema7>;
    required?: infer R;
} ? InferRequireds<P, R extends readonly string[] ? R : []> & InferOptionals<P, R extends readonly string[] ? R : []> : NoFields;
type InferAdditionals<T extends JSONObjectSchema7> = T extends {
    additionalProperties: false;
} ? NoFields : T extends {
    additionalProperties?: true;
} ? JsonObject : T extends {
    additionalProperties: infer A;
} ? {
    [extra: string]: Infer<A> | undefined;
} : JsonObject;
type InferFromObjectSchema<T extends JSONObjectSchema7> = Resolve<InferBaseObject<T> & InferAdditionals<T>>;
type InferFromArraySchema<T extends JSONSchema7> = T extends {
    items: infer U;
} ? Infer<U>[] : Json[];
type InferFromSchema<T extends JSONSchema7> = JSONSchema7 extends T ? JsonObject : T extends {
    type: "object";
} ? InferFromObjectSchema<T> : T extends {
    type: "array";
} ? InferFromArraySchema<T> : T extends {
    oneOf: readonly (infer U)[];
} ? Infer<U> : T extends {
    anyOf: readonly (infer U)[];
} ? Infer<U> : T extends {
    allOf: readonly JSONSchema7[];
} ? InferAllOf<T["allOf"]> : T extends {
    not: JSONSchema7;
} ? Json : T extends {
    enum: readonly (infer U)[];
} ? U : T extends {
    const: infer C;
} ? C : T extends {
    type: "string";
} ? string : T extends {
    type: "number";
} ? number : T extends {
    type: "integer";
} ? number : T extends {
    type: "boolean";
} ? boolean : T extends {
    type: "null";
} ? null : Json;

type AiToolTypePack<A extends JsonObject = JsonObject, R extends JsonObject = JsonObject> = {
    A: A;
    R: R;
};
type AskUserMessageInChatOptions = Omit<AiGenerationOptions, "tools" | "knowledge">;
type SetToolResultOptions = Omit<AiGenerationOptions, "tools" | "knowledge">;
type AiToolInvocationProps<A extends JsonObject, R extends JsonObject> = Resolve<DistributiveOmit<AiToolInvocationPart<A, R>, "type"> & {
    respond: (...args: OptionalTupleUnless<R, [result: ToolResultResponse<R>]>) => void;
    /**
     * These are the inferred types for your tool call which you can pass down
     * to UI components, like so:
     *
     *     <AiTool.Confirmation
     *       types={types}
     *       confirm={
     *         // Now fully type-safe!
     *         (args) => result
     *       } />
     *
     * This will make your AiTool.Confirmation component aware of the types for
     * `args` and `result`.
     */
    types: AiToolTypePack<A, R>;
    [kInternal]: {
        execute: AiToolExecuteCallback<A, R> | undefined;
    };
}>;
type AiOpaqueToolInvocationProps = AiToolInvocationProps<JsonObject, JsonObject>;
type AiToolExecuteContext = {
    name: string;
    invocationId: string;
};
type AiToolExecuteCallback<A extends JsonObject, R extends JsonObject> = (args: A, context: AiToolExecuteContext) => Record<string, never> extends R ? Awaitable<ToolResultResponse<R> | undefined | void> : Awaitable<ToolResultResponse<R>>;
type AiToolDefinition<S extends JSONObjectSchema7, A extends JsonObject, R extends JsonObject> = {
    description?: string;
    parameters: S;
    execute?: AiToolExecuteCallback<A, R>;
    render?: (props: AiToolInvocationProps<A, R>) => unknown;
};
type AiOpaqueToolDefinition = AiToolDefinition<JSONObjectSchema7, JsonObject, JsonObject>;
/**
 * Helper function to help infer the types of `args`, `render`, and `result`.
 * This function has no runtime implementation and is only needed to make it
 * possible for TypeScript to infer types.
 */
declare function defineAiTool<R extends JsonObject>(): <const S extends JSONObjectSchema7>(def: AiToolDefinition<S, InferFromSchema<S> extends JsonObject ? InferFromSchema<S> : JsonObject, R>) => AiOpaqueToolDefinition;
type NavigationInfo = {
    /**
     * The message ID of the parent message, or null if there is no parent.
     */
    parent: MessageId | null;
    /**
     * The message ID of the left sibling message, or null if there is no left sibling.
     */
    prev: MessageId | null;
    /**
     * The message ID of the right sibling message, or null if there is no right sibling.
     */
    next: MessageId | null;
};
type WithNavigation<T> = T & {
    navigation: NavigationInfo;
};
type UiChatMessage = WithNavigation<AiChatMessage>;
type AiContext = {
    staticSessionInfoSig: Signal<StaticSessionInfo | null>;
    dynamicSessionInfoSig: Signal<DynamicSessionInfo | null>;
    pendingCmds: Map<CmdId, {
        resolve: (value: ServerAiMsg) => void;
        reject: (reason: unknown) => void;
    }>;
    chatsStore: ReturnType<typeof createStore_forUserAiChats>;
    toolsStore: ReturnType<typeof createStore_forTools>;
    messagesStore: ReturnType<typeof createStore_forChatMessages>;
    knowledge: KnowledgeStack;
};
type LayerKey = Brand<string, "LayerKey">;
declare class KnowledgeStack {
    #private;
    constructor();
    registerLayer(uniqueLayerId: string): LayerKey;
    deregisterLayer(layerKey: LayerKey): void;
    get(): AiKnowledgeSource[];
    invalidate(): void;
    updateKnowledge(layerKey: LayerKey, key: string, data: AiKnowledgeSource | null): void;
}
declare function createStore_forTools(): {
    getToolDescriptions: (chatId: string) => AiToolDescription[];
    getToolΣ: (name: string, chatId?: string) => DerivedSignal<AiOpaqueToolDefinition | undefined>;
    registerTool: (name: string, tool: AiOpaqueToolDefinition, chatId?: string) => () => void;
};
declare function createStore_forChatMessages(toolsStore: ReturnType<typeof createStore_forTools>, setToolResultFn: (chatId: string, messageId: MessageId, invocationId: string, result: ToolResultResponse, options?: SetToolResultOptions) => Promise<void>): {
    getMessageById: (messageId: MessageId) => AiChatMessage | undefined;
    getChatMessagesForBranchΣ: (chatId: string, branch?: MessageId) => DerivedSignal<UiChatMessage[]>;
    createOptimistically: {
        (chatId: string, role: "user", parentId: MessageId | null, content: AiUserContentPart[]): MessageId;
        (chatId: string, role: "assistant", parentId: MessageId | null): MessageId;
    };
    upsert: (message: AiChatMessage) => void;
    upsertMany: (messages: AiChatMessage[]) => void;
    remove: (chatId: string, messageId: MessageId) => void;
    removeByChatId: (chatId: string) => void;
    addDelta: (messageId: MessageId, delta: AiAssistantDeltaUpdate) => void;
    failAllPending: () => void;
    markMine(messageId: MessageId): void;
};
declare function createStore_forUserAiChats(): {
    chatsΣ: DerivedSignal<AiChat[]>;
    getChatById: (chatId: string) => AiChat | undefined;
    upsert: (chat: AiChat) => void;
    upsertMany: (chats: AiChat[]) => void;
    markDeleted: (chatId: string) => void;
};
/** @private This API will change, and is not considered stable. DO NOT RELY on it. */
type Ai = {
    [kInternal]: {
        context: AiContext;
    };
    connectInitially: () => void;
    disconnect: () => void;
    getStatus: () => Status;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    getChats: (options?: {
        cursor?: Cursor;
    }) => Promise<GetChatsResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    getOrCreateChat: (
    /** A unique identifier for the chat. */
    chatId: string, options?: CreateChatOptions) => Promise<GetOrCreateChatResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    deleteChat: (chatId: string) => Promise<DeleteChatResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    getMessageTree: (chatId: string) => Promise<GetMessageTreeResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    deleteMessage: (chatId: string, messageId: MessageId) => Promise<DeleteMessageResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    clearChat: (chatId: string) => Promise<ClearChatResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    askUserMessageInChat: (chatId: string, userMessage: MessageId | {
        id: MessageId;
        parentMessageId: MessageId | null;
        content: AiUserContentPart[];
    }, targetMessageId: MessageId, options?: AskUserMessageInChatOptions) => Promise<AskInChatResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    abort: (messageId: MessageId) => Promise<AbortAiResponse>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    setToolResult: (chatId: string, messageId: MessageId, invocationId: string, result: ToolResultResponse, options?: SetToolResultOptions) => Promise<void>;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    signals: {
        chatsΣ: DerivedSignal<AiChat[]>;
        getChatMessagesForBranchΣ(chatId: string, branch?: MessageId): DerivedSignal<UiChatMessage[]>;
        getToolΣ(name: string, chatId?: string): DerivedSignal<AiOpaqueToolDefinition | undefined>;
    };
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    getChatById: (chatId: string) => AiChat | undefined;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    registerKnowledgeLayer: (uniqueLayerId: string) => LayerKey;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    deregisterKnowledgeLayer: (layerKey: LayerKey) => void;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    updateKnowledge: (layerKey: LayerKey, data: AiKnowledgeSource, key?: string) => void;
    /** @private This API will change, and is not considered stable. DO NOT RELY on it. */
    registerTool: (name: string, tool: AiOpaqueToolDefinition, chatId?: string) => () => void;
};

type CommentBodyParagraphElementArgs = {
    /**
     * The paragraph element.
     */
    element: CommentBodyParagraph;
    /**
     * The text content of the paragraph.
     */
    children: string;
};
type CommentBodyTextElementArgs = {
    /**
     * The text element.
     */
    element: CommentBodyText;
};
type CommentBodyLinkElementArgs = {
    /**
     * The link element.
     */
    element: CommentBodyLink;
    /**
     * The absolute URL of the link.
     */
    href: string;
};
type CommentBodyMentionElementArgs<U extends BaseUserMeta = DU> = {
    /**
     * The mention element.
     */
    element: CommentBodyMention;
    /**
     * The mention's user info, if the `resolvedUsers` option was provided.
     */
    user?: U["info"];
};
type StringifyCommentBodyElements<U extends BaseUserMeta = DU> = {
    /**
     * The element used to display paragraphs.
     */
    paragraph: (args: CommentBodyParagraphElementArgs, index: number) => string;
    /**
     * The element used to display text elements.
     */
    text: (args: CommentBodyTextElementArgs, index: number) => string;
    /**
     * The element used to display links.
     */
    link: (args: CommentBodyLinkElementArgs, index: number) => string;
    /**
     * The element used to display mentions.
     */
    mention: (args: CommentBodyMentionElementArgs<U>, index: number) => string;
};
type StringifyCommentBodyOptions<U extends BaseUserMeta = DU> = {
    /**
     * Which format to convert the comment to.
     */
    format?: "plain" | "html" | "markdown";
    /**
     * The elements used to customize the resulting string. Each element has
     * priority over the defaults inherited from the `format` option.
     */
    elements?: Partial<StringifyCommentBodyElements<U>>;
    /**
     * The separator used between paragraphs.
     */
    separator?: string;
    /**
     * A function that returns user info from user IDs.
     * You should return a list of user objects of the same size, in the same order.
     */
    resolveUsers?: (args: ResolveUsersArgs) => Awaitable<(U["info"] | undefined)[] | undefined>;
};
declare function isCommentBodyText(element: CommentBodyElement): element is CommentBodyText;
declare function isCommentBodyMention(element: CommentBodyElement): element is CommentBodyMention;
declare function isCommentBodyLink(element: CommentBodyElement): element is CommentBodyLink;
/**
 * Get an array of all mentions in a `CommentBody`.
 *
 * Narrow results with an optional predicate, e.g.
 * `(mention) => mention.kind === "user"` to only get user mentions.
 */
declare function getMentionsFromCommentBody(body: CommentBody, predicate?: (mention: CommentBodyMention) => boolean): CommentBodyMention[];
declare function resolveUsersInCommentBody<U extends BaseUserMeta>(body: CommentBody, resolveUsers?: (args: ResolveUsersArgs) => Awaitable<(U["info"] | undefined)[] | undefined>): Promise<Map<string, U["info"]>>;
declare function htmlSafe(value: string): HtmlSafeString;
declare class HtmlSafeString {
    #private;
    constructor(strings: readonly string[], values: readonly (string | string[] | HtmlSafeString | HtmlSafeString[])[]);
    toString(): string;
}
/**
 * Build an HTML string from a template literal where the values are escaped.
 * Nested calls are supported and won't be escaped.
 */
declare function html(strings: TemplateStringsArray, ...values: (string | string[] | HtmlSafeString | HtmlSafeString[])[]): string;
/**
 * Helper function to convert a URL (relative or absolute) to an absolute URL.
 *
 * @param url The URL to convert to an absolute URL (relative or absolute).
 * @returns The absolute URL or undefined if the URL is invalid.
 */
declare function toAbsoluteUrl(url: string): string | undefined;
/**
 * Convert a `CommentBody` into either a plain string,
 * Markdown, HTML, or a custom format.
 */
declare function stringifyCommentBody(body: CommentBody, options?: StringifyCommentBodyOptions<BaseUserMeta>): Promise<string>;

declare function generateCommentUrl({ roomUrl, commentId, }: {
    roomUrl: string;
    commentId: string;
}): string;

/**
 * Converts a plain comment data object (usually returned by the API) to a comment data object that can be used by the client.
 * This is necessary because the plain data object stores dates as ISO strings, but the client expects them as Date objects.
 * @param data The plain comment data object (usually returned by the API)
 * @returns The rich comment data object that can be used by the client.
 */
declare function convertToCommentData(data: CommentDataPlain): CommentData;
/**
 * Converts a plain thread data object (usually returned by the API) to a thread data object that can be used by the client.
 * This is necessary because the plain data object stores dates as ISO strings, but the client expects them as Date objects.
 * @param data The plain thread data object (usually returned by the API)
 * @returns The rich thread data object that can be used by the client.
 */
declare function convertToThreadData<M extends BaseMetadata>(data: ThreadDataPlain<M>): ThreadData<M>;
/**
 * Converts a plain comment reaction object (usually returned by the API) to a comment reaction object that can be used by the client.
 * This is necessary because the plain data object stores dates as ISO strings, but the client expects them as Date objects.
 * @param data The plain comment reaction object (usually returned by the API)
 * @returns The rich comment reaction object that can be used by the client.
 */
declare function convertToCommentUserReaction(data: CommentUserReactionPlain): CommentUserReaction;
/**
 * Converts a plain inbox notification data object (usually returned by the API) to an inbox notification data object that can be used by the client.
 * This is necessary because the plain data object stores dates as ISO strings, but the client expects them as Date objects.
 * @param data The plain inbox notification data object (usually returned by the API)
 * @returns The rich inbox notification data object that can be used by the client.
 */
declare function convertToInboxNotificationData(data: InboxNotificationDataPlain): InboxNotificationData;
/**
 * Converts a plain subscription data object (usually returned by the API) to a subscription data object that can be used by the client.
 * This is necessary because the plain data object stores dates as ISO strings, but the client expects them as Date objects.
 * @param data The plain subscription data object (usually returned by the API)
 * @returns The rich subscription data object that can be used by the client.
 */
declare function convertToSubscriptionData(data: SubscriptionDataPlain): SubscriptionData;
/**
 * Converts a plain user subscription data object (usually returned by the API) to a user subscription data object that can be used by the client.
 * This is necessary because the plain data object stores dates as ISO strings, but the client expects them as Date objects.
 * @param data The plain user subscription data object (usually returned by the API)
 * @returns The rich user subscription data object that can be used by the client.
 */
declare function convertToUserSubscriptionData(data: UserSubscriptionDataPlain): UserSubscriptionData;

/**
 * Lookup table for nodes (= SerializedCrdt values) by their IDs.
 */
type NodeMap = Map<string, // Node ID
SerializedCrdt>;
/**
 * Reverse lookup table for all child nodes (= list of SerializedCrdt values)
 * by their parent node's IDs.
 */
type ParentToChildNodeMap = Map<string, // Parent's node ID
IdTuple<SerializedChild>[]>;

declare function isLiveNode(value: unknown): value is LiveNode;
declare function cloneLson<L extends Lson | undefined>(value: L): L;

declare function lsonToJson(value: Lson): Json;
declare function patchLiveObjectKey<O extends LsonObject, K extends keyof O, V extends Json>(liveObject: LiveObject<O>, key: K, prev?: V, next?: V): void;
declare function legacy_patchImmutableObject<TState extends JsonObject>(state: TState, updates: StorageUpdate[]): TState;

/**
 * Like `new AbortController()`, but where the result can be unpacked
 * safely, i.e. `const { signal, abort } = makeAbortController()`.
 *
 * This unpacking is unsafe to do with a regular `AbortController` because
 * the `abort` method is not bound to the controller instance.
 *
 * In addition to this, you can also pass an optional (external)
 * AbortSignal to "wrap", in which case the returned signal will be in
 * aborted state when either the signal is aborted externally or
 * internally.
 */
declare function makeAbortController(externalSignal?: AbortSignal): {
    signal: AbortSignal;
    abort: (reason?: unknown) => void;
};

/**
 * Helper function that can be used to implement exhaustive switch statements
 * with TypeScript. Example usage:
 *
 *    type Fruit = "🍎" | "🍌";
 *
 *    switch (fruit) {
 *      case "🍎":
 *      case "🍌":
 *        return doSomething();
 *
 *      default:
 *        return assertNever(fruit, "Unknown fruit");
 *    }
 *
 * If now the Fruit union is extended (i.e. add "🍒"), TypeScript will catch
 * this *statically*, rather than at runtime, and force you to handle the
 * 🍒 case.
 */
declare function assertNever(_value: never, errmsg: string): never;
/**
 * Asserts that a certain condition holds. If it does not hold, will throw
 * a runtime error in dev mode.
 *
 * In production, nothing is asserted and this acts as a no-op.
 */
declare function assert(condition: boolean, errmsg: string): asserts condition;
/**
 * Asserts that a given value is non-nullable. This is similar to TypeScript's
 * `!` operator, but will throw an error at runtime (dev-mode only) indicating
 * an incorrect assumption.
 *
 * Instead of:
 *
 *     foo!.bar
 *
 * Use:
 *
 *     nn(foo).bar
 *
 */
declare function nn<T>(value: T, errmsg?: string): NonNullable<T>;

declare class HttpError extends Error {
    response: Response;
    details?: JsonObject;
    private constructor();
    static fromResponse(response: Response): Promise<HttpError>;
    /**
     * Convenience accessor for response.status.
     */
    get status(): number;
}
/**
 * Wraps a promise factory. Will create promises until one succeeds. If
 * a promise rejects, it will retry calling the factory for at most `maxTries`
 * times. Between each attempt, it will inject a a backoff delay (in millis)
 * from the given array. If the array contains fewer items then `maxTries`,
 * then the last backoff number will be used indefinitely.
 *
 * If the last attempt is rejected too, the returned promise will fail too.
 *
 * @param promiseFn The promise factory to execute
 * @param maxTries The number of total tries (must be >=1)
 * @param backoff An array of timings to inject between each promise attempt
 * @param shouldStopRetrying An optional function to not auto-retry on certain errors
 */
declare function autoRetry<T>(promiseFn: () => Promise<T>, maxTries: number, backoff: number[], shouldStopRetrying?: (err: any) => boolean): Promise<T>;

declare function chunk<T>(array: T[], size: number): T[][];

type ControlledPromise<T> = {
    promise: Promise<T>;
    resolve: (value: T) => void;
    reject: (reason: unknown) => void;
};
/**
 * Drop-in replacement for the ES2024 Promise.withResolvers() API.
 */
declare function Promise_withResolvers<T>(): ControlledPromise<T>;

declare function createThreadId(): string;
declare function createCommentId(): string;
declare function createCommentAttachmentId(): string;
declare function createInboxNotificationId(): string;

/**
 * Like ES6 map, but takes a default (factory) function which will be used
 * to create entries for missing keys on the fly.
 *
 * Useful for code like:
 *
 *   const map = new DefaultMap(() => []);
 *   map.getOrCreate('foo').push('hello');
 *   map.getOrCreate('foo').push('world');
 *   map.getOrCreate('foo')
 *   // ['hello', 'world']
 *
 */
declare class DefaultMap<K, V> extends Map<K, V> {
    #private;
    /**
     * If the default function is not provided to the constructor, it has to be
     * provided in each .getOrCreate() call individually.
     */
    constructor(defaultFn?: (key: K) => V, entries?: readonly (readonly [K, V])[] | null);
    /**
     * Gets the value at the given key, or creates it.
     *
     * Difference from normal Map: if the key does not exist, it will be created
     * on the fly using the factory function, and that value will get returned
     * instead of `undefined`.
     */
    getOrCreate(key: K, defaultFn?: (key: K) => V): V;
}

/**
 * Displays a deprecation warning in the dev console. Only in dev mode, and
 * only once per message/key. In production, this is a no-op.
 */
declare function deprecate(message: string, key?: string): void;
/**
 * Conditionally displays a deprecation warning in the dev
 * console if the first argument is truthy. Only in dev mode, and
 * only once per message/key. In production, this is a no-op.
 */
declare function deprecateIf(condition: unknown, message: string, key?: string): void;
/**
 * Throws a deprecation error in the dev console.
 *
 * Only triggers in dev mode. In production, this is a no-op.
 */
declare function throwUsageError(message: string): void;
/**
 * Conditionally throws a usage error in the dev console if the first argument
 * is truthy. Use this to "escalate" usage patterns that in previous versions
 * we already warned about with deprecation warnings.
 *
 * Only has effect in dev mode. In production, this is a no-op.
 */
declare function errorIf(condition: unknown, message: string): void;

/**
 * A Deque (= Double Ended Queue) is like a stack, but where elements can be
 * efficiently pushed or popped from either side.
 *
 * The following calls are equivalent with arrays (but insertions are O(n)
 * instead of O(n^2)):
 *
 * - deque.push(1)              ⇔  array.push(1)
 * - deque.push([1, 2, 3])      ⇔  array.push(1, 2, 3)
 * - deque.push(many)           ⇔  array.push(...many)
 * - deque.pop()                ⇔  array.pop()
 *
 * - deque.pushLeft(1)          ⇔  array.unshift(1)
 * - deque.pushLeft([1, 2, 3])  ⇔  array.unshift(1, 2, 3)
 * - deque.pushLeft(many)       ⇔  array.unshift(...many)
 * - deque.popLeft()            ⇔  array.shift()
 *
 */
declare class Deque<T> {
    #private;
    constructor();
    get length(): number;
    [Symbol.iterator](): IterableIterator<T>;
    push(value: T | readonly T[]): void;
    pop(): T | undefined;
    pushLeft(value: T | readonly T[]): void;
    popLeft(): T | undefined;
}

declare const warn: (message: string, ...args: readonly unknown[]) => void;
declare const error: (message: string, ...args: readonly unknown[]) => void;
declare const warnWithTitle: (title: string, message: string, ...args: readonly unknown[]) => void;
declare const errorWithTitle: (title: string, message: string, ...args: readonly unknown[]) => void;

declare const fancyConsole_error: typeof error;
declare const fancyConsole_errorWithTitle: typeof errorWithTitle;
declare const fancyConsole_warn: typeof warn;
declare const fancyConsole_warnWithTitle: typeof warnWithTitle;
declare namespace fancyConsole {
  export { fancyConsole_error as error, fancyConsole_errorWithTitle as errorWithTitle, fancyConsole_warn as warn, fancyConsole_warnWithTitle as warnWithTitle };
}

/**
 * Freezes the given argument, but only in development builds. In production
 * builds, this is a no-op for performance reasons.
 */
declare const freeze: typeof Object.freeze;

declare function isPlainObject(blob: unknown): blob is {
    [key: string]: unknown;
};
/**
 * Check if value is of shape { startsWith: string }
 */
declare function isStartsWithOperator(blob: unknown): blob is {
    startsWith: string;
};

declare const nanoid: (t?: number) => string;

/**
 * Converts an object to a query string
 * Example:
 * ```ts
 * const query = objectToQuery({
 *   resolved: true,
 *   metadata: {
 *     status: "open",
 *     priority: 3,
 *     org: {
 *       startsWith: "liveblocks:",
 *     },
 *   },
 * });
 *
 * console.log(query);
 * // resolved:true AND metadata["status"]:open AND metadata["priority"]:3 AND metadata["org"]^"liveblocks:"
 * ```
 */
type SimpleFilterValue = string | number | boolean | null;
type OperatorFilterValue = {
    startsWith: string;
};
type FilterValue = SimpleFilterValue | OperatorFilterValue;
declare function objectToQuery(obj: {
    [key: string]: FilterValue | {
        [key: string]: FilterValue | undefined;
    } | undefined;
}): string;

type Poller = {
    /**
     * Increments the subscriber count for this poller. If it becomes > 0, the
     * poller will be enabled.
     */
    inc(): void;
    /**
     * Decrements the subscriber count for this poller. If it becomes = 0, the
     * poller will be disabled.
     */
    dec(): void;
    /**
     * Polls immediately only if it has been more than `maxStaleTimeMs` milliseconds since
     * the last poll and no poll is currently in progress. After polling, schedules
     * the next poll at the regular interval.
     */
    pollNowIfStale(): void;
    /**
     * Marks the poller as stale. This can be used to force the next call
     * to `.pollNowIfStale()` to poll immediately.
     */
    markAsStale(): void;
};
/**
 * Makes a poller that will call `await callback()` at the desired interval (in
 * millis).
 *
 * The poller has only three public APIs, all side effects:
 * - .inc(): void
 * - .dec(): void
 * - .pollNowIfStale(): void
 *
 * It has the following behaviors/guarantees:
 * - Performing a "poll" literally means calling the provided callback (and
 *   awaiting it)
 * - It will only ever start polling if .inc() was called (more often than .dec())
 * - It will not _immediately_ poll if .inc() is called. The first poll
 *   can be expected no earlier than the specified interval.
 * - If .dec() is called as many times as .inc(), it stops the poller. This
 *   means that any next poll will get unscheduled. If .dev() is called while
 *   a poll is ongoing, it will still finish that poll, but after that stop
 *   further polling.
 * - If the document's visibility state changes to hidden (tab is moved to the
 *   background), polling will be paused until the document's made visible again
 * - If the document becomes visible again, the poller will:
 *   - Still do nothing if the poller isn't enabled
 *   - Still do nothing if the poller is enabled, but the last time a poll
 *     happened recently enough (= less than the maxStaleTimeMs, which defaults
 *     to infinity)
 *   - Trigger a poll right away otherwise. If an existing poll was already
 *     scheduled, think of it as if this future poll is "earlied" and just
 *     happening right now instead
 */
declare function makePoller(callback: (signal: AbortSignal) => Promise<void> | void, intervalMs: number, options?: {
    maxStaleTimeMs?: number;
}): Poller;

/**
 * Positions, aka the Pos type, are efficient encodings of "positions" in
 * a list, using the following printable subset of the ASCII alphabet:
 *
 *    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
 *   ^                                                                                             ^
 *   Lowest digit                                                                      Highest digit
 *
 * Each Pos is a sequence of characters from the above alphabet, conceptually
 * codifying a floating point number 0 < n < 1. For example, the string "31007"
 * would be used to represent the number 0.31007, except that this
 * representation uses base 96.
 *
 *   0 ≃ ' '  (lowest digit)
 *   1 ≃ '!'
 *   2 ≃ '"'
 *   ...
 *   9 ≃ '~'  (highest digit)
 *
 * So think:
 *   '!'    ≃ 0.1
 *   '"'    ≃ 0.2
 *   '!"~'  ≃ 0.129
 *
 * Three rules:
 * - All "characters" in the string should be valid digits (from the above
 *   alphabet)
 * - The value 0.0 is not a valid Pos value
 * - A Pos cannot have trailing "zeroes"
 *
 * This representation has the following benefits:
 *
 * 1. It's always possible to get a number that lies before, after, or between
 *    two arbitrary Pos values.
 * 2. Pos values can be compared using normal string comparison.
 *
 * Some examples:
 * - '!'  < '"'   (like how .1  < .2)
 * - '!'  < '~'   (like how .1  < .9)
 * - '!!' < '!~'  (like how .11 < .19)
 * - '~!' < '~~'  (like how .91 < .99)
 * - '~'  < '~!'  (like how .9  < .91)
 * - '!!' < '!O'  (like how .1  < .5)
 * - '!O' < '!~'  (like how .5  < .9)
 *
 */

/**
 * A valid/verified "position" string. These values are used as "parentKey"s by
 * LiveList children, and define their relative ordering.
 */
type Pos = Brand<string, "Pos">;
/**
 * Given two positions, returns the position value that lies in the middle.
 * When given only a high bound, computes the canonical position "before" it.
 * When given only a low bound, computes the canonical position "after" it.
 * When given no bounds at all, returns the "first" canonical position.
 */
declare function makePosition(x?: Pos, y?: Pos): Pos;
/**
 * Checks that a str is a valid Pos, and converts it to the nearest valid one
 * if not.
 */
declare function asPos(str: string): Pos;

/**
 * Shallowly compares two given values.
 *
 * - Two simple values are considered equal if they're strictly equal
 * - Two arrays are considered equal if their members are strictly equal
 * - Two objects are considered equal if their values are strictly equal
 *
 * Testing goes one level deep.
 */
declare function shallow(a: unknown, b: unknown): boolean;
/**
 * Two-level deep shallow check.
 * Useful for checking equality of { isLoading: false, myData: [ ... ] } like
 * data structures, where you want to do a shallow comparison on the "data"
 * key.
 *
 * NOTE: Works on objects only, not on arrays!
 */
declare function shallow2(a: unknown, b: unknown): boolean;

/**
 * A datastructure to keep elements in ascending order, as defined by the "less
 * than" function you provide. The elements will be ordered according to
 * whatever you define as the "less than" for this element type, so that every
 * element is less than its successor in the list.
 *
 * const sorted = SortedList.from(
 *   [{ id: 4 }, { id: 1 }, { id: 9 }, { id: 4 }],
 *   (a, b) => a.id < b.id)
 * )
 * sorted.add({ id: 5 })
 * sorted.remove({ id: 4 })  // Assuming it's the same obj ref!
 *
 * Array.from(sorted)
 * [{ id: 1 }, { id: 4 }, { id: 5 }, { id: 9 }])
 */
declare class SortedList<T> {
    #private;
    private constructor();
    static with<T>(lt: (a: T, b: T) => boolean): SortedList<T>;
    static from<T>(arr: readonly T[], lt: (a: T, b: T) => boolean): SortedList<T>;
    static fromAlreadySorted<T>(alreadySorted: T[], lt: (a: T, b: T) => boolean): SortedList<T>;
    /**
     * Clones the sorted list to a new instance.
     */
    clone(): SortedList<T>;
    /**
     * Adds a new item to the sorted list, such that it remains sorted.
     */
    add(value: T): void;
    /**
     * Removes all values from the sorted list, making it empty again.
     * Returns whether the list was mutated or not.
     */
    clear(): boolean;
    /**
     * Removes the first value matching the predicate.
     * Returns whether the list was mutated or not.
     */
    removeBy(predicate: (item: T) => boolean, limit?: number): boolean;
    /**
     * Removes the given value from the sorted list, if it exists. The given
     * value must be `===` to one of the list items. Only the first entry will be
     * removed if the element exists in the sorted list multiple times.
     *
     * Returns whether the list was mutated or not.
     */
    remove(value: T): boolean;
    at(index: number): T | undefined;
    get length(): number;
    filter(predicate: (value: T) => boolean): IterableIterator<T>;
    findAllRight(predicate: (value: T, index: number) => unknown): IterableIterator<T>;
    [Symbol.iterator](): IterableIterator<T>;
    iterReversed(): IterableIterator<T>;
    /** Finds the leftmost item that matches the predicate. */
    find(predicate: (value: T, index: number) => unknown, start?: number): T | undefined;
    /** Finds the leftmost index that matches the predicate. */
    findIndex(predicate: (value: T, index: number) => unknown, start?: number): number;
    /** Finds the rightmost item that matches the predicate. */
    findRight(predicate: (value: T, index: number) => unknown, start?: number): T | undefined;
    /** Finds the rightmost index that matches the predicate. */
    findIndexRight(predicate: (value: T, index: number) => unknown, start?: number): number;
    get rawArray(): readonly T[];
}

/**
 * Like JSON.stringify(), but using stable (sorted) object key order, so that
 * it returns the same value for the same keys, no matter their order.
 */
declare function stableStringify(value: unknown): string;

type QueryParams = Record<string, string | number | null | undefined> | URLSearchParams;
/**
 * Concatenates a path to an existing URL.
 */
declare function urljoin(baseUrl: string | URL, path: string, params?: QueryParams): string;
/**
 * A string that is guaranteed to be URL safe (where all arguments are properly
 * encoded), only obtainable as the result of using `url` template strings.
 */
type URLSafeString = Brand<string, "URLSafeString">;
/**
 * Builds a URL where each "hole" in the template string will automatically be
 * encodeURIComponent()-escaped, so it's impossible to build invalid URLs.
 */
declare function url(strings: TemplateStringsArray, ...values: string[]): URLSafeString;

/**
 * Definition of all messages the Panel can send to the Client.
 */
type PanelToClientMessage = 
/**
 * Initial message from the panel to the client, used for two purposes.
 * 1. First, it’s eavesdropped by the background script, which uses this
 *    message to register a "port", which sets up a channel for two-way
 *    communication between panel and client for the remainder of the time.
 * 2. It signifies to the client that the devpanel is listening.
 */
{
    msg: "connect";
}
/**
 * Expresses to the client that the devtool is interested in
 * receiving the "sync stream" for the room. The sync stream
 * that follows is an initial "full sync", followed by many
 * "partial" syncs, happening for every update.
 */
 | {
    msg: "room::subscribe";
    roomId: string;
}
/**
 * Expresses to the client that the devtool no longer is
 * interested in the "sync stream" for a room, for example,
 * because the devtools panel is closed, or if it switched to
 * a different room.
 */
 | {
    msg: "room::unsubscribe";
    roomId: string;
};
/**
 * Definition of all messages the Client can send to the Panel.
 */
type ClientToPanelMessage = 
/**
 * Initial message sent by the client to test if a dev panel is listening.
 * This is necessary in cases where the dev panel is already opened and
 * listened, before the client is loaded. If the panel receives this message,
 * it will replay its initial "connect" message, which triggers the loading
 * of the two-way connection.
 */
{
    msg: "wake-up-devtools";
}
/**
 * Sent when a new room is available for the dev panel to track and watch.
 * Sent by the client as soon as the room is attempted to be entered. This
 * happens _before_ the actual connection to the room server is established,
 * meaning the room is visible to the devtools even while it is connecting.
 */
 | {
    msg: "room::available";
    roomId: string;
    clientVersion: string;
}
/**
 * Sent when a room is left and the client loses track of the room instance.
 */
 | {
    msg: "room::unavailable";
    roomId: string;
}
/**
 * Sent initially, to synchronize the entire current state of the room.
 */
 | {
    msg: "room::sync::full";
    roomId: string;
    status: Status;
    storage: readonly LsonTreeNode[] | null;
    me: UserTreeNode | null;
    others: readonly UserTreeNode[];
}
/**
 * Sent whenever something about the internals of a room changes.
 */
 | {
    msg: "room::sync::partial";
    roomId: string;
    status?: Status;
    storage?: readonly LsonTreeNode[];
    me?: UserTreeNode;
    others?: readonly UserTreeNode[];
}
/**
 * Sent whenever an user room event is emitted in the room.
 */
 | {
    msg: "room::events::custom-event";
    roomId: string;
    event: CustomEventTreeNode;
}
/**
 * Sent whenever the ydoc is updated
 */
 | {
    msg: "room::sync::ydoc";
    roomId: string;
    update: YDocUpdateServerMsg | UpdateYDocClientMsg;
};
type FullPanelToClientMessage = PanelToClientMessage & {
    source: "liveblocks-devtools-panel";
    tabId: number;
};
type FullClientToPanelMessage = ClientToPanelMessage & {
    source: "liveblocks-devtools-client";
};

type protocol_ClientToPanelMessage = ClientToPanelMessage;
type protocol_FullClientToPanelMessage = FullClientToPanelMessage;
type protocol_FullPanelToClientMessage = FullPanelToClientMessage;
type protocol_PanelToClientMessage = PanelToClientMessage;
declare namespace protocol {
  export type { protocol_ClientToPanelMessage as ClientToPanelMessage, protocol_FullClientToPanelMessage as FullClientToPanelMessage, protocol_FullPanelToClientMessage as FullPanelToClientMessage, protocol_PanelToClientMessage as PanelToClientMessage };
}

/**
 * Helper type to help users adopt to Lson types from interface definitions.
 * You should only use this to wrap interfaces you don't control. For more
 * information, see
 * https://liveblocks.io/docs/guides/limits#lson-constraint-and-interfaces
 */
type EnsureJson<T> = T extends Json ? T : T extends Array<infer I> ? (EnsureJson<I>)[] : [
    unknown
] extends [T] ? Json | undefined : T extends Date ? string : T extends (...args: any[]) => any ? never : {
    [K in keyof T as EnsureJson<T[K]> extends never ? never : K]: EnsureJson<T[K]>;
};

export { type AckOp, type ActivityData, type AiAssistantContentPart, type AiAssistantMessage, type AiChat, type AiChatMessage, type AiKnowledgeSource, type AiOpaqueToolDefinition, type AiOpaqueToolInvocationProps, type AiReasoningPart, type AiTextPart, type AiToolDefinition, type AiToolExecuteCallback, type AiToolExecuteContext, type AiToolInvocationPart, type AiToolInvocationProps, type AiToolTypePack, type AiUserMessage, type AsyncError, type AsyncLoading, type AsyncResult, type AsyncSuccess, type Awaitable, type BaseActivitiesData, type BaseAuthResult, type BaseMetadata, type BaseRoomInfo, type BaseUserMeta, type Brand, type BroadcastEventClientMsg, type BroadcastOptions, type BroadcastedEventServerMsg, type Client, type ClientMsg, ClientMsgCode, type ClientOptions, type CommentAttachment, type CommentBody, type CommentBodyBlockElement, type CommentBodyElement, type CommentBodyInlineElement, type CommentBodyLink, type CommentBodyLinkElementArgs, type CommentBodyMention, type CommentBodyMentionElementArgs, type CommentBodyParagraph, type CommentBodyParagraphElementArgs, type CommentBodyText, type CommentBodyTextElementArgs, type CommentData, type CommentDataPlain, type CommentLocalAttachment, type CommentMixedAttachment, type CommentReaction, type CommentUserReaction, type CommentUserReactionPlain, type CommentsEventServerMsg, type ContextualPromptContext, type ContextualPromptResponse, type CopilotId, CrdtType, type CreateListOp, type CreateManagedPoolOptions, type CreateMapOp, type CreateObjectOp, type CreateOp, type CreateRegisterOp, type Cursor, type CustomAuthenticationResult, type DAD, type DE, type DM, type DP, type DRI, type DS, type DU, DefaultMap, type Delegates, type DeleteCrdtOp, type DeleteObjectKeyOp, Deque, DerivedSignal, DevToolsTreeNode as DevTools, protocol as DevToolsMsg, type DistributiveOmit, type EnsureJson, type EnterOptions, type EventSource, type FetchStorageClientMsg, type FetchYDocClientMsg, type GetThreadsOptions, type History, type HistoryVersion, HttpError, type ISignal, type IUserInfo, type IWebSocket, type IWebSocketCloseEvent, type IWebSocketEvent, type IWebSocketInstance, type IWebSocketMessageEvent, type IYjsProvider, type IdTuple, type Immutable, type InboxNotificationCustomData, type InboxNotificationCustomDataPlain, type InboxNotificationData, type InboxNotificationDataPlain, type InboxNotificationDeleteInfo, type InboxNotificationTextMentionData, type InboxNotificationTextMentionDataPlain, type InboxNotificationThreadData, type InboxNotificationThreadDataPlain, type InferFromSchema, type InitialDocumentStateServerMsg, type Json, type JsonArray, type JsonObject, type JsonScalar, type KDAD, type LargeMessageStrategy, LiveList, type LiveListUpdate, LiveMap, type LiveMapUpdate, type LiveNode, LiveObject, type LiveObjectUpdate, type LiveStructure, LiveblocksError, type LiveblocksErrorContext, type LostConnectionEvent, type Lson, type LsonObject, type ManagedPool, type MentionData, type MessageId, MutableSignal, type NoInfr, type NodeMap, type NotificationChannel, type NotificationChannelSettings, type NotificationKind, type NotificationSettings, type NotificationSettingsPlain, type Observable, type Op, OpCode, type OpaqueClient, type OpaqueRoom, type OptionalTupleUnless, type OthersEvent, type ParentToChildNodeMap, type PartialNotificationSettings, type PartialUnless, type Patchable, Permission, type PlainLson, type PlainLsonFields, type PlainLsonList, type PlainLsonMap, type PlainLsonObject, type Poller, type PrivateClientApi, type PrivateRoomApi, Promise_withResolvers, type QueryMetadata, type QueryParams, type RejectedStorageOpServerMsg, type Relax, type RenderableToolResultResponse, type Resolve, type ResolveMentionSuggestionsArgs, type ResolveRoomsInfoArgs, type ResolveUsersArgs, type Room, type RoomEventMessage, type RoomStateServerMsg, type RoomSubscriptionSettings, type SerializedChild, type SerializedCrdt, type SerializedList, type SerializedMap, type SerializedObject, type SerializedRegister, type SerializedRootObject, type ServerMsg, ServerMsgCode, type SetParentKeyOp, Signal, type SignalType, SortedList, type Status, type StorageStatus, type StorageUpdate, type StringifyCommentBodyElements, type StringifyCommentBodyOptions, type SubscriptionData, type SubscriptionDataPlain, type SubscriptionDeleteInfo, type SubscriptionDeleteInfoPlain, type SubscriptionKey, type SyncSource, type SyncStatus, TextEditorType, type ThreadData, type ThreadDataPlain, type ThreadDataWithDeleteInfo, type ThreadDeleteInfo, type ToImmutable, type ToJson, type ToolResultResponse, type URLSafeString, type UnsubscribeCallback, type UpdateObjectOp, type UpdatePresenceClientMsg, type UpdatePresenceServerMsg, type UpdateStorageClientMsg, type UpdateStorageServerMsg, type UpdateYDocClientMsg, type UploadAttachmentOptions, type User, type UserJoinServerMsg, type UserLeftServerMsg, type UserMentionData, type UserRoomSubscriptionSettings, type UserSubscriptionData, type UserSubscriptionDataPlain, WebsocketCloseCodes, type WithNavigation, type YDocUpdateServerMsg, type YjsSyncStatus, ackOp, asPos, assert, assertNever, autoRetry, b64decode, batch, checkBounds, chunk, cloneLson, compactObject, fancyConsole as console, convertToCommentData, convertToCommentUserReaction, convertToInboxNotificationData, convertToSubscriptionData, convertToThreadData, convertToUserSubscriptionData, createClient, createCommentAttachmentId, createCommentId, createInboxNotificationId, createManagedPool, createNotificationSettings, createThreadId, defineAiTool, deprecate, deprecateIf, detectDupes, entries, errorIf, freeze, generateCommentUrl, getMentionsFromCommentBody, getSubscriptionKey, html, htmlSafe, isChildCrdt, isCommentBodyLink, isCommentBodyMention, isCommentBodyText, isJsonArray, isJsonObject, isJsonScalar, isLiveNode, isNotificationChannelEnabled, isPlainObject, isRootCrdt, isStartsWithOperator, kInternal, keys, legacy_patchImmutableObject, lsonToJson, makeAbortController, makeEventSource, makePoller, makePosition, mapValues, memoizeOnSuccess, nanoid, nn, objectToQuery, patchLiveObjectKey, patchNotificationSettings, raise, resolveUsersInCommentBody, shallow, shallow2, stableStringify, stringifyCommentBody, throwUsageError, toAbsoluteUrl, toPlainLson, tryParseJson, url, urljoin, wait, withTimeout };
