{"version":3,"file":"index.mjs","names":["ConnectionState","#_storage","ConnectionState","#_storage"],"sources":["../src/AbstractStorageStore.ts","../src/constants.ts","../src/PluvProcedure.ts","../src/CrdtManager.ts","../src/CrdtNotifier.ts","../src/EventNotifier.ts","../src/ListenerManager.ts","../src/PluvRouter.ts","../src/StateNotifier.ts","../src/StorageStore.ts","../src/utils/debounce.ts","../src/utils/pickBy.ts","../src/UsersManager.ts","../src/UsersNotifier.ts","../src/PluvRoom.ts","../src/PluvClient.ts","../src/createClient.ts","../src/infer.ts","../src/MockedRoom.ts","../src/register.ts"],"sourcesContent":["export abstract class AbstractStorageStore {\n    public room: string;\n\n    constructor(room: string) {\n        this.room = room;\n    }\n\n    public abstract addUpdate(update: string): Promise<void>;\n\n    public abstract destroy(): Promise<void>;\n\n    public abstract flatten(encodedState: string): Promise<void>;\n\n    public abstract getShouldFlatten(): Promise<boolean>;\n\n    public abstract getUpdates(start?: number): Promise<readonly string[]>;\n\n    public abstract initialize(): Promise<void>;\n}\n","export const MAX_PRESENCE_SIZE_BYTES = 512;\nexport const PLUV_PRESENCE_META_KEY = \"__pluv\";\n","import type { AbstractCrdtDocFactory, InferDocLike } from \"@pluv/crdt\";\nimport type { EventRecord, IOLike, InputZodLike, JsonObject, ProcedureLike } from \"@pluv/types\";\nimport type { EventResolver, MergeEventRecords } from \"./types\";\n\nexport interface PluvProcedureConfig<\n    TIO extends IOLike,\n    TInput extends JsonObject,\n    TOutput extends EventRecord<string, any>,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n> {\n    broadcast?: EventResolver<TIO, TInput, TOutput, TPresence, InferDocLike<TCrdt>> | null;\n    input?: InputZodLike<TInput>;\n}\n\nexport class PluvProcedure<\n    TIO extends IOLike,\n    TInput extends JsonObject,\n    TOutput extends EventRecord<string, any>,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TFilled extends \"input\" | \"broadcast\" | \"\",\n> implements ProcedureLike<TInput, TOutput> {\n    private _broadcast: EventResolver<\n        TIO,\n        TInput,\n        Partial<TOutput>,\n        TPresence,\n        InferDocLike<TCrdt>\n    > | null = null;\n    private _input: InputZodLike<TInput> | null = null;\n\n    public get config(): ProcedureLike<TInput, TOutput>[\"config\"] {\n        return {\n            broadcast: this._broadcast?.bind(this) ?? null,\n            input: this._input ?? null,\n            resolver: this._resolver(),\n        } as ProcedureLike<TInput, TOutput>[\"config\"];\n    }\n\n    constructor(config: PluvProcedureConfig<TIO, TInput, TOutput, TPresence, TCrdt> = {}) {\n        const { broadcast, input } = config;\n\n        this._broadcast = broadcast ?? null;\n        this._input = input ?? null;\n    }\n\n    public broadcast<TResult extends EventRecord<string, any> = {}>(\n        resolver: EventResolver<TIO, TInput, TResult, TPresence, InferDocLike<TCrdt>>,\n    ): Omit<\n        PluvProcedure<\n            TIO,\n            TInput,\n            MergeEventRecords<[TOutput, TResult]>,\n            TPresence,\n            TCrdt,\n            TFilled | \"input\" | \"broadcast\"\n        >,\n        TFilled | \"input\" | \"broadcast\"\n    > {\n        const { broadcast } = this.config;\n\n        if (!!broadcast) throw new Error(\"Broadcast was already defined for this procedure\");\n\n        return new PluvProcedure<\n            TIO,\n            TInput,\n            MergeEventRecords<[TOutput, TResult]>,\n            TPresence,\n            TCrdt,\n            TFilled | \"input\" | \"broadcast\"\n        >({\n            ...(this.config as any),\n            broadcast: resolver as any,\n        });\n    }\n\n    public input<TData extends JsonObject>(\n        input: InputZodLike<TData>,\n    ): Omit<PluvProcedure<TIO, TData, {}, TPresence, TCrdt, TFilled | \"input\">, TFilled | \"input\"> {\n        return new PluvProcedure<TIO, TData, {}, TPresence, TCrdt, TFilled | \"input\">({ input });\n    }\n\n    private _resolver(): EventResolver<TIO, TInput, TOutput, TPresence, InferDocLike<TCrdt>> {\n        return (data, context) => this._broadcast?.(data, context) as TOutput;\n    }\n}\n","import type { AbstractCrdtDocFactory, InferDocLike, InferStorage } from \"@pluv/crdt\";\nimport { noop } from \"@pluv/crdt\";\n\nexport type CrdtManagerOptions<TCrdt extends AbstractCrdtDocFactory<any, any>> = {\n    initialStorage?: TCrdt;\n};\n\ninterface CrdtManagerInitializeParams {\n    origin?: any;\n    update: string | readonly string[];\n}\n\ninterface ApplyUpdateParams {\n    origin?: any;\n    update: string | readonly string[];\n}\n\nexport class CrdtManager<TCrdt extends AbstractCrdtDocFactory<any, any>> {\n    public doc: InferDocLike<TCrdt>;\n    public initialized: boolean = false;\n\n    private readonly _docFactory: TCrdt;\n\n    constructor(options: CrdtManagerOptions<TCrdt>) {\n        const { initialStorage = noop.doc({}) as any } = options;\n\n        this._docFactory = initialStorage;\n        this.doc = this._docFactory.getEmpty() as InferDocLike<TCrdt>;\n    }\n\n    /**\n     * !HACK\n     * @description If this is called before the doc is initialized. Omit the\n     * update. This unfortunately means updates can be dropped entirely\n     * @date June 13, 2023\n     */\n    public applyUpdate(params: ApplyUpdateParams): this {\n        const { origin, update } = params;\n\n        if (!this.initialized) return this;\n\n        const updates: readonly string[] = typeof update === \"string\" ? [update] : update;\n\n        this._applyDocUpdates(this.doc, updates, origin);\n\n        return this;\n    }\n\n    public destroy(): void {\n        this.initialized = false;\n        this.doc.destroy();\n        this.doc = this._docFactory.getEmpty() as InferDocLike<TCrdt>;\n    }\n\n    public get<TKey extends keyof InferStorage<TCrdt>>(key: TKey): InferStorage<TCrdt>[TKey] {\n        return this.doc.get(key);\n    }\n\n    public getInitialState(): string {\n        return this._docFactory.getInitialized().getEncodedState();\n    }\n\n    public initialize(params: CrdtManagerInitializeParams): this {\n        const { origin, update } = params;\n\n        /**\n         * !HACK\n         * @description If the doc was already initialized, we don't want to re-initialize\n         * the doc and overwrite what's already there. Skip the initialization and log a\n         * warning.\n         * @date May 7, 2025\n         */\n        if (this.initialized) {\n            console.warn(\"Attempted to initialize storage multiple times\");\n            return this;\n        }\n\n        /**\n         * !HACK\n         * @description If the doc is already populated, somehow we're attempting to overwrite\n         * a doc that was presumably initialized but not identified as initialized. Skip the\n         * initialization and log a warning.\n         * @date May 7, 2025\n         */\n        if (!this.doc.isEmpty()) {\n            console.warn(\"Attempted to initialize over a non-empty storage\");\n            return this;\n        }\n\n        const updates = typeof update === \"string\" ? [update] : update;\n\n        if (!updates.length) return this;\n\n        const initialized = this._docFactory.getInitialized();\n        const reference = initialized.get();\n\n        this.doc = this._applyDocUpdates(this.doc, updates, origin).rebuildStorage(reference);\n        this.initialized = true;\n        initialized.destroy();\n\n        return this;\n    }\n\n    public resolveEncodedState(updates: string | string[] | readonly string[]): string | null {\n        return this._docFactory.resolveEncodedState(updates);\n    }\n\n    private _applyDocUpdates(\n        doc: InferDocLike<TCrdt>,\n        updates: readonly string[],\n        origin?: string,\n    ): InferDocLike<TCrdt> {\n        doc.transact(() => {\n            doc.batchApplyEncodedState({ origin, updates });\n        }, origin);\n\n        return doc;\n    }\n}\n","import type { CrdtType, InferCrdtJson } from \"@pluv/crdt\";\nimport type { StorageSubscriptionCallback } from \"@pluv/types\";\nimport type { Subject } from \"wonka\";\nimport { makeSubject, subscribe } from \"wonka\";\n\nexport class CrdtNotifier<TStorage extends Record<string, CrdtType<any, any>>> {\n    public rootSubject = makeSubject<{\n        [P in keyof TStorage]: InferCrdtJson<TStorage[P]>;\n    }>();\n\n    public subjects = new Map<\n        keyof TStorage,\n        Subject<InferCrdtJson<TStorage[keyof TStorage]>> | null\n    >();\n\n    public subject<TKey extends keyof TStorage>(key: TKey): Subject<InferCrdtJson<TStorage[TKey]>> {\n        const subject = this.subjects.get(key);\n\n        if (subject) {\n            return subject as Subject<InferCrdtJson<TStorage[TKey]>>;\n        }\n\n        const newSubject = makeSubject<InferCrdtJson<TStorage[TKey]>>();\n\n        this.subjects.set(key, newSubject);\n\n        return newSubject as Subject<InferCrdtJson<TStorage[TKey]>>;\n    }\n\n    public subcribeRoot(\n        callback: (value: {\n            [P in keyof TStorage]: InferCrdtJson<TStorage[P]>;\n        }) => void,\n    ): () => void {\n        return subscribe(callback)(this.rootSubject.source).unsubscribe;\n    }\n\n    public subscribe<TKey extends keyof TStorage>(\n        key: TKey,\n        callback: StorageSubscriptionCallback<TStorage, TKey>,\n    ): () => void {\n        const subject = this.subject(key);\n\n        return subscribe(callback)(subject.source).unsubscribe;\n    }\n}\n","import type {\n    EventNotifierSubscriptionCallback,\n    Id,\n    InferIOOutput,\n    IOEventMessage,\n    IOLike,\n} from \"@pluv/types\";\nimport type { Subject } from \"wonka\";\nimport { makeSubject, subscribe } from \"wonka\";\n\nexport class EventNotifier<TIO extends IOLike> {\n    public subjects = new Map<\n        keyof InferIOOutput<TIO>,\n        Subject<Id<IOEventMessage<TIO, keyof InferIOOutput<TIO>>>>\n    >();\n\n    public subject<TEvent extends keyof InferIOOutput<TIO>>(\n        name: TEvent,\n    ): Subject<Id<IOEventMessage<TIO, TEvent>>> {\n        const subject = this.subjects.get(name);\n\n        if (subject) return subject;\n\n        const newSubject = makeSubject<Id<IOEventMessage<TIO, TEvent>>>();\n\n        this.subjects.set(name, newSubject);\n\n        return newSubject;\n    }\n\n    public subscribe<TEvent extends keyof InferIOOutput<TIO>>(\n        name: TEvent,\n        callback: EventNotifierSubscriptionCallback<TIO, TEvent>,\n    ): () => void {\n        const subject = this.subject(name);\n\n        return subscribe(callback)(subject.source).unsubscribe;\n    }\n}\n","import { makeSubject, subscribe, TypeOfSource } from \"wonka\";\n\nexport class ListenerManager {\n    public subjects = {\n        close: makeSubject<CloseEvent>(),\n        error: makeSubject<Event>(),\n        message: makeSubject<MessageEvent<any>>(),\n        open: makeSubject<Event>(),\n    };\n\n    public subscribe<TKind extends keyof typeof this.subjects>(\n        kind: TKind,\n        callback: (event: TypeOfSource<(typeof this.subjects)[TKind][\"source\"]>) => void,\n    ): () => void {\n        const source = this.subjects[kind]?.source;\n\n        if (!source) return () => undefined;\n\n        return subscribe(callback)(source as any).unsubscribe;\n    }\n}\n","import type { AbstractCrdtDocFactory } from \"@pluv/crdt\";\nimport type { IOLike, IORouterLike, JsonObject } from \"@pluv/types\";\nimport type { PluvProcedure } from \"./PluvProcedure\";\n\nexport type PluvRouterEventConfig<\n    TIO extends IOLike,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n> = { [P: string]: Pick<PluvProcedure<TIO, any, any, TPresence, TCrdt, \"\">, \"config\"> };\n\nexport type MergedRouter<\n    TRouters extends PluvRouter<TIO, TPresence, TCrdt, any>[],\n    TIO extends IOLike,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TRoot extends TRouters[0][\"_defs\"][\"events\"],\n> = TRouters extends [\n    infer IHead extends PluvRouter<TIO, TPresence, TCrdt, any>,\n    ...infer ITail extends PluvRouter<TIO, TPresence, TCrdt, any>[],\n]\n    ? MergedRouter<ITail, TIO, TPresence, TCrdt, TRoot & IHead[\"_defs\"][\"events\"]>\n    : PluvRouter<TIO, TPresence, TCrdt, TRoot>;\n\nexport class PluvRouter<\n    TIO extends IOLike,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TEvents extends PluvRouterEventConfig<TIO, TPresence, TCrdt> = {},\n> implements IORouterLike<TEvents> {\n    readonly _defs: { events: TEvents } = { events: {} as TEvents };\n\n    constructor(events: TEvents) {\n        const invalidName = Object.keys(events).find((name) => !this._isValidEventName(name));\n\n        if (typeof invalidName === \"string\") {\n            throw new Error(\n                `Invalid event name. Event names must be formatted as valid JavaScript variable names: \"${invalidName}\"`,\n            );\n        }\n\n        this._defs = { events };\n    }\n\n    public static merge<\n        TRouters extends PluvRouter<TIO, TPresence, TCrdt, any>[],\n        TIO extends IOLike,\n        TPresence extends Record<string, any>,\n        TCrdt extends AbstractCrdtDocFactory<any, any>,\n    >(...routers: TRouters): MergedRouter<TRouters, TIO, TPresence, TCrdt, {}> {\n        const events = Object.assign(\n            Object.create(null),\n            ...routers.map((router) => router._defs.events),\n        );\n\n        if (Object.keys(events).some((key) => key.startsWith(\"$\"))) {\n            throw new Error('Procedures may not start with \"$\"');\n        }\n\n        return new PluvRouter<any, any, any, any>(events) as MergedRouter<\n            TRouters,\n            TIO,\n            TPresence,\n            TCrdt,\n            {}\n        >;\n    }\n\n    private _isValidEventName(name: string): boolean {\n        return /^[a-z_$][a-z0-9_$]*$/gi.test(name);\n    }\n}\n","import type {\n    Id,\n    IOLike,\n    JsonObject,\n    StateNotifierSubjects,\n    SubscriptionCallback,\n    UserInfo,\n    WebSocketState,\n} from \"@pluv/types\";\nimport type { Subject } from \"wonka\";\nimport { makeSubject, subscribe } from \"wonka\";\n\ntype InferSubjectValue<\n    TIO extends IOLike,\n    TPresence extends Record<string, any>,\n    TSubject extends keyof StateNotifierSubjects<TIO, TPresence>,\n> =\n    StateNotifierSubjects<TIO, TPresence>[TSubject] extends Subject<infer IValue>\n        ? Id<IValue>\n        : never;\n\nexport class StateNotifier<TIO extends IOLike, TPresence extends Record<string, any> = {}> {\n    public subjects: StateNotifierSubjects<TIO, TPresence> = {\n        connection: makeSubject<Id<WebSocketState<TIO>>>(),\n        \"my-presence\": makeSubject<TPresence>(),\n        myself: makeSubject<Readonly<Id<UserInfo<TIO, TPresence>>> | null>(),\n        others: makeSubject<readonly Id<UserInfo<TIO, TPresence>>[]>(),\n        \"storage-loaded\": makeSubject<true>(),\n    };\n\n    public subscribe<TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(\n        name: TSubject,\n        callback: SubscriptionCallback<TIO, TPresence, TSubject>,\n    ): () => void {\n        const source = this.subjects[name]?.source as any;\n\n        if (!source) throw new Error(`Could not subscribe to source: ${name}`);\n\n        return subscribe(callback)(source).unsubscribe;\n    }\n}\n","import { AbstractStorageStore } from \"./AbstractStorageStore\";\n\nexport class StorageStore extends AbstractStorageStore {\n    public addUpdate() {\n        return Promise.resolve();\n    }\n\n    public applyUpdates() {\n        return Promise.resolve();\n    }\n\n    public destroy() {\n        return Promise.resolve();\n    }\n\n    public flatten() {\n        return Promise.resolve();\n    }\n\n    public getShouldFlatten() {\n        return Promise.resolve(false);\n    }\n\n    public getUpdates() {\n        return Promise.resolve([]);\n    }\n\n    public initialize() {\n        return Promise.resolve();\n    }\n}\n","export const debounce = <TFunc extends (...args: any[]) => any>(\n    fn: TFunc,\n    options?: { wait: number; immediate?: boolean },\n): ((...args: Parameters<TFunc>) => void) => {\n    const { wait, immediate = false } = options ?? {};\n\n    let prevResult: ReturnType<TFunc> | undefined;\n    let timeout: number | null = null;\n\n    return (...args: Parameters<TFunc>): void => {\n        if (typeof timeout === \"number\") clearTimeout(timeout);\n\n        timeout = setTimeout(() => {\n            timeout = null;\n\n            if (!immediate) prevResult = fn(args);\n        }, wait) as number;\n\n        if (immediate && !timeout) {\n            fn(args);\n\n            return;\n        }\n\n        return prevResult;\n    };\n};\n","export const pickBy = <T extends Record<string, any>>(\n    obj: T,\n    by: (value: T[keyof T]) => boolean,\n): Partial<T> => {\n    const result: Partial<T> = {};\n    const keys: (keyof T)[] = Object.keys(obj);\n\n    for (let i = 0; i < keys.length; ++i) {\n        const key = keys[i];\n        const value = obj[key];\n\n        if (by(value)) result[key] = value;\n    }\n\n    return result;\n};\n","import type { InputZodLike, IOLike, JsonObject, OptionalProps, UserInfo } from \"@pluv/types\";\nimport { PLUV_PRESENCE_META_KEY } from \"./constants\";\nimport type { PluvClientLimits } from \"./types\";\nimport { pickBy } from \"./utils\";\n\nexport type Presence = Record<string, unknown>;\n\nexport type UsersManagerConfig<TPresence extends Record<string, any> = {}> = {\n    initialPresence?: TPresence;\n    limits: PluvClientLimits;\n    presence?: InputZodLike<TPresence>;\n};\n\nexport type AddConnectionResult<TIO extends IOLike, TPresence extends Record<string, any> = {}> = {\n    clientId: string;\n    data: UserInfo<TIO, TPresence>;\n    isMyself: boolean;\n    remaining: number;\n};\n\nexport type DeleteConnectionResult<\n    TIO extends IOLike,\n    TPresence extends Record<string, any> = {},\n> = {\n    clientId: string;\n    data: UserInfo<TIO, TPresence>;\n    remaining: number;\n};\n\nexport class UsersManager<TIO extends IOLike, TPresence extends Record<string, any> = {}> {\n    public readonly initialPresence: TPresence;\n\n    private readonly _idMap = {\n        fromConnectionId: new Map<[connectionId: string][0], [clientId: string][0]>(),\n        fromClientId: new Map<[clientId: string][0], Set<[connectionId: string][0]>>(),\n    };\n    private _limits: PluvClientLimits;\n    /**\n     * @description This presence can be updated while the user is not\n     * connected.\n     */\n    private _myPresence: TPresence;\n    /**\n     * @description This is only set when the user is connected.\n     */\n    private _myself: UserInfo<TIO, TPresence> | null = null;\n    private _others = new Map<[clientId: string][0], UserInfo<TIO, TPresence>>();\n    private _presence: InputZodLike<TPresence> | null = null;\n\n    constructor(config: UsersManagerConfig<TPresence>) {\n        const { initialPresence, limits, presence = null } = config;\n\n        this.initialPresence = initialPresence as TPresence;\n\n        this._limits = limits;\n        this._myPresence = initialPresence as TPresence;\n        this._presence = presence;\n    }\n\n    public get myPresence(): TPresence {\n        return this._myPresence;\n    }\n\n    public get myself(): UserInfo<TIO, TPresence> | null {\n        return this._myself;\n    }\n\n    public addConnection(\n        userInfo: OptionalProps<UserInfo<TIO, TPresence>, \"presence\">,\n    ): AddConnectionResult<TIO, TPresence> {\n        /**\n         * @description Ensure that the presence is complete, so that it does not fail schema\n         * validation\n         * @date April 20, 2025\n         */\n        const cleaned = pickBy(userInfo.presence ?? {}, (value) => typeof value !== \"undefined\");\n        const presence = { ...this.initialPresence, ...cleaned };\n        const data: UserInfo<TIO, TPresence> = { ...userInfo, presence };\n\n        const myClientId = !!this._myself ? this.getClientId(this._myself) : null;\n        const clientId = this.getClientId(data);\n        const remaining = this._setConnectionId(userInfo.connectionId, clientId).size;\n\n        if (myClientId === clientId) {\n            const result: AddConnectionResult<TIO, TPresence> = {\n                clientId,\n                data,\n                isMyself: true,\n                remaining,\n            };\n\n            return result;\n        }\n\n        const other = this._others.get(clientId);\n\n        /**\n         * !HACK\n         * @description Don't override the other user, so that we ensure the user's presence isn't\n         * overwritten by whatever incoming connection.\n         * @date April 16, 2025\n         */\n        if (!other) this._others.set(clientId, data);\n\n        const result: AddConnectionResult<TIO, TPresence> = {\n            clientId,\n            data,\n            isMyself: false,\n            remaining,\n        };\n\n        return result;\n    }\n\n    public clearConnections(): void {\n        this.removeMyself();\n        this._others.clear();\n        this._idMap.fromClientId.clear();\n        this._idMap.fromConnectionId.clear();\n    }\n\n    public deleteConnection(connectionId: string): DeleteConnectionResult<TIO, TPresence> | null {\n        const clientId = this.getClientId(connectionId);\n\n        this._deleteConnectionId(connectionId);\n\n        // We expect that a clientId should always exist here, but we'll just check this anyways\n        if (!clientId) return null;\n\n        const userInfo = this._others.get(clientId) ?? null;\n\n        // We also expect this should always exist here, but we'll just check this anyways\n        if (!userInfo) return null;\n\n        const remaining = this._getConnectionIds(clientId)?.size ?? 0;\n        const result: DeleteConnectionResult<TIO, TPresence> = {\n            clientId,\n            remaining,\n            data: userInfo,\n        };\n\n        /**\n         * @description A user may have multiple websocket connections open. If one connection is\n         * dropped, the user may still be connected via another websocket (e.g. on anther browser\n         * tab). In this case, we just want to remove the connection mapping for the connection\n         * that is dropped, but keep the remaining connections and the user.\n         * @date April 16, 2025\n         */\n        if (!remaining) this._others.delete(clientId);\n\n        return result;\n    }\n\n    /**\n     * @description The client id is either the user's id (if authorized) or the connection id\n     * otherwise. This is so that, despite having multiple connections, the user will only have one\n     * presence to all other users.\n     * @date April 16, 2025\n     */\n    public getClientId(connectionId: string): string | null;\n    public getClientId(userInfo: UserInfo<TIO, TPresence>): string;\n    public getClientId(input: string | UserInfo<TIO, TPresence>): string | null {\n        if (typeof input !== \"string\") {\n            const userInfo = input;\n            const connectionId = userInfo.connectionId;\n            const userId = userInfo.user?.id ?? null;\n\n            return userId ?? connectionId;\n        }\n\n        const connectionId = input;\n\n        if (this._myself?.connectionId === connectionId) {\n            return this.getClientId(this._myself);\n        }\n\n        const clientId = this._idMap.fromConnectionId.get(connectionId) ?? null;\n\n        return clientId;\n    }\n\n    public getOther(connectionId: string): UserInfo<TIO, TPresence> | null {\n        const clientId = this.getClientId(connectionId);\n\n        if (!clientId) return null;\n\n        return this._others.get(clientId) ?? null;\n    }\n\n    public getOthers(): readonly UserInfo<TIO, TPresence>[] {\n        return Array.from(this._others.values());\n    }\n\n    public patchPresence(connectionId: string, patch: Partial<TPresence>): TPresence | null {\n        const clientId = this.getClientId(connectionId);\n        const myClientId = !!this._myself ? this.getClientId(this._myself) : null;\n\n        if (!clientId) return null;\n        if (myClientId === clientId) return this.updateMyPresence(patch);\n\n        const other = this._others.get(clientId);\n\n        if (!other) return null;\n\n        const cleanedPatch = pickBy(patch ?? {}, (value) => typeof value !== \"undefined\");\n        const cleanedPresence = pickBy(\n            other.presence ?? {},\n            (value) => typeof value !== \"undefined\",\n        );\n        const presence = {\n            ...this.initialPresence,\n            ...cleanedPresence,\n            ...cleanedPatch,\n        } as TPresence;\n        const validated = this._presence ? this._presence.parse(presence) : presence;\n\n        /**\n         * !HACK\n         * @description We're patching internal metadata back into the presence field so it doesn't\n         * get stripped from validation\n         * @date May 13, 2025\n         */\n        if (!!presence[PLUV_PRESENCE_META_KEY]) {\n            (validated as any)[PLUV_PRESENCE_META_KEY] = presence[PLUV_PRESENCE_META_KEY];\n        }\n\n        this._others.set(clientId, { ...other, presence: validated });\n\n        return validated;\n    }\n\n    public removeMyself(): void {\n        if (!this._myself) return;\n\n        const connectionId = this._myself.connectionId;\n\n        this._deleteConnectionId(connectionId);\n        this._myself = null;\n    }\n\n    public setMyself(userInfo: OptionalProps<UserInfo<TIO, TPresence>, \"presence\">): void {\n        const connectionId = userInfo.connectionId;\n        const presence = userInfo.presence ?? this.initialPresence;\n\n        this._myself = { ...userInfo, presence };\n        this._myPresence = presence;\n\n        const clientId = this.getClientId(this._myself);\n\n        this._setConnectionId(connectionId, clientId);\n    }\n\n    public setPresence(connectionId: string, presence: TPresence): void {\n        const clientId = this.getClientId(connectionId);\n        const myClientId = !!this._myself ? this.getClientId(this._myself) : null;\n\n        if (!clientId) return;\n\n        if (myClientId === clientId) {\n            if (!this._myself) return;\n\n            this._myself.presence = presence;\n            this._myPresence = presence;\n\n            return;\n        }\n\n        const other = this._others.get(clientId);\n\n        if (!other) return;\n\n        this._others.set(clientId, { ...other, presence });\n    }\n\n    /**\n     * @description This method need not care about being connected. This is because a user should\n     * be able to view and update their own presence without being online\n     * @date April 20, 2025\n     */\n    public updateMyPresence(patch: Partial<TPresence>): TPresence {\n        const cleanedPatch = pickBy(patch, (value) => typeof value !== \"undefined\");\n        const cleanedPresence = pickBy(this._myPresence, (value) => typeof value !== \"undefined\");\n        const updated = {\n            ...this.initialPresence,\n            ...cleanedPresence,\n            ...cleanedPatch,\n        } as TPresence;\n        const bytes = new TextEncoder().encode(JSON.stringify(updated)).length;\n\n        if (!!this._limits.presenceMaxSize && bytes > this._limits.presenceMaxSize) {\n            throw new Error(\n                `Large presence. Presence must be at most 512 bytes. Current size: ${bytes.toLocaleString()}`,\n            );\n        }\n\n        this._myPresence = updated;\n\n        if (!this._myself) return updated;\n\n        this._myself.presence = updated;\n\n        return updated;\n    }\n\n    private _deleteConnectionId(connectionId: string): void {\n        const clientId = this.getClientId(connectionId);\n\n        this._idMap.fromConnectionId.delete(connectionId);\n\n        if (!clientId) return;\n\n        const set = this._idMap.fromClientId.get(clientId) ?? null;\n\n        if (!set) return;\n\n        set.delete(connectionId);\n\n        if (!!set.size) return;\n\n        this._idMap.fromClientId.delete(clientId);\n    }\n\n    private _getConnectionIds(clientId: string): Set<[connectionId: string][0]> | null {\n        const set = this._idMap.fromClientId.get(clientId);\n\n        return set ?? null;\n    }\n\n    private _setConnectionId(\n        connectionId: string,\n        clientId: string,\n    ): Set<[connectionId: string][0]> {\n        const set = this._idMap.fromClientId.get(clientId) ?? new Set<string>();\n        const updated = set.add(connectionId);\n\n        this._idMap.fromConnectionId.set(connectionId, clientId);\n        this._idMap.fromClientId.set(clientId, updated);\n\n        return updated;\n    }\n}\n","import type {\n    Id,\n    IOLike,\n    JsonObject,\n    OtherSubscriptionCallback,\n    OthersSubscriptionCallback,\n    OthersSubscriptionEvent,\n    UserInfo,\n} from \"@pluv/types\";\nimport type { Subject } from \"wonka\";\nimport { makeSubject, subscribe, TypeOfSource } from \"wonka\";\n\nexport class UsersNotifier<TIO extends IOLike, TPresence extends Record<string, any> = {}> {\n    public readonly others = makeSubject<{\n        others: readonly Id<UserInfo<TIO, TPresence>>[];\n        event: OthersSubscriptionEvent<TIO, TPresence>;\n    }>();\n\n    private _otherSubjects = new Map<\n        [clientId: string][0],\n        Subject<Id<UserInfo<TIO, TPresence>> | null>\n    >();\n\n    public clear(): void {\n        this._otherSubjects.forEach((subject) => {\n            subject.next(null);\n        });\n\n        this._otherSubjects.clear();\n    }\n\n    public delete(clientId: string): void {\n        this.other(clientId).next(null);\n        this._otherSubjects.delete(clientId);\n    }\n\n    public other(clientId: string): Subject<Id<UserInfo<TIO, TPresence>> | null> {\n        const subject = this._otherSubjects.get(clientId);\n\n        if (subject) return subject;\n\n        const newSubject = makeSubject<Id<UserInfo<TIO, TPresence>>>();\n\n        this._otherSubjects.set(clientId, newSubject);\n\n        return newSubject;\n    }\n\n    public subscribeOther(\n        clientId: string,\n        callback: OtherSubscriptionCallback<TIO, TPresence>,\n    ): () => void {\n        const source = this.other(clientId).source;\n        const subscription = subscribe(callback)(source);\n\n        return subscription.unsubscribe;\n    }\n\n    public subscribeOthers(callback: OthersSubscriptionCallback<TIO, TPresence>): () => void {\n        const subscription = subscribe<TypeOfSource<typeof this.others.source>>(\n            ({ others, event }) => callback(others, event),\n        )(this.others.source);\n\n        return subscription.unsubscribe;\n    }\n}\n","import type {\n    AbstractCrdtDocFactory,\n    InferCrdtJson,\n    InferDoc,\n    InferDocLike,\n    InferStorage,\n    NoopCrdtDocFactory,\n} from \"@pluv/crdt\";\nimport type {\n    BaseIOEventRecord,\n    BaseUser,\n    BroadcastProxy,\n    CrdtDocLike,\n    EventMessage,\n    EventNotifierSubscriptionCallback,\n    EventProxy,\n    IOEventMessage,\n    IOLike,\n    Id,\n    InferIOAuthorize,\n    InferIOAuthorizeUser,\n    InferIOInput,\n    InferIOOutput,\n    InputZodLike,\n    JsonObject,\n    MergeEvents,\n    OptionalProps,\n    OtherSubscriptionCallback,\n    OthersSubscriptionCallback,\n    RoomEventListenerMap,\n    RoomLike,\n    StateNotifierSubjects,\n    StorageProxy,\n    StorageRootSubscriptionCallback,\n    StorageSubscriptionCallback,\n    SubscribeProxy,\n    SubscriptionCallback,\n    UpdateMyPresenceAction,\n    UserInfo,\n    WebSocketConnection,\n    WebSocketState,\n} from \"@pluv/types\";\nimport { ConnectionState, StorageState } from \"@pluv/types\";\nimport type { AbstractStorageStore } from \"./AbstractStorageStore\";\nimport type { CrdtManagerOptions } from \"./CrdtManager\";\nimport { CrdtManager } from \"./CrdtManager\";\nimport { CrdtNotifier } from \"./CrdtNotifier\";\nimport { EventNotifier } from \"./EventNotifier\";\nimport { ListenerManager } from \"./ListenerManager\";\nimport { PluvProcedure } from \"./PluvProcedure\";\nimport type { PluvRouterEventConfig } from \"./PluvRouter\";\nimport { PluvRouter } from \"./PluvRouter\";\nimport { StateNotifier } from \"./StateNotifier\";\nimport { StorageStore } from \"./StorageStore\";\nimport type {\n    AuthorizationState,\n    EventResolver,\n    EventResolverContext,\n    InternalSubscriptions,\n    PluvClientLimits,\n    PublicKey,\n    WithMetadata,\n} from \"./types\";\nimport type { UsersManagerConfig } from \"./UsersManager\";\nimport { UsersManager } from \"./UsersManager\";\nimport { UsersNotifier } from \"./UsersNotifier\";\nimport { debounce } from \"./utils\";\n\nconst ADD_TO_STORAGE_STATE_DEBOUNCE_MS = 1_000;\nconst HEARTBEAT_INTERVAL_MS = 10_000;\nconst PONG_TIMEOUT_MS = 2_000;\n\nconst RECONNECT_TIMEOUT_MS = 5_000;\nconst MIN_RECONNECT_TIMEOUT_MS = 1_000;\nconst MAX_RECONNECT_TIMEOUT_MS = 60_000;\n\nconst ORIGIN_INITIALIZED = \"$initialized\";\nconst ORIGIN_STORAGE_UPDATED = \"$storageUpdated\";\n\ndeclare global {\n    var process: {\n        env: {\n            [key: string]: string | undefined;\n        };\n    };\n}\n\nexport const DEFAULT_PLUV_CLIENT_ADDON = <\n    TIO extends IOLike,\n    TMetadata extends JsonObject,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n>(\n    input: PluvRoomAddonInput<TIO, TMetadata, TPresence, TCrdt>,\n): PluvRoomAddonResult => ({\n    storage: new StorageStore(input.room.id),\n});\n\ninterface WindowListeners {\n    onNavigatorOffline: () => void;\n    onNavigatorOnline: () => void;\n    onVisibilityChange: () => void;\n    onWindowFocus: () => void;\n}\n\ninterface WebSocketListeners {\n    onClose: (event: CloseEvent) => void;\n    onError: (event: Event) => void;\n    onMessage: (message: MessageEvent<string>) => void;\n    onOpen: (event: Event) => void;\n}\n\ninterface IntervalIds {\n    heartbeat: number | null;\n}\n\ninterface TimeoutIds {\n    pong: number | null;\n    reconnect: number | null;\n}\n\nexport interface EndpointParams<TMetadata extends JsonObject> {\n    metadata: TMetadata;\n    room: string;\n}\nexport type AuthEndpoint<TMetadata extends JsonObject> =\n    | string\n    | ((params: EndpointParams<TMetadata>) => string | FetchOptions)\n    | true;\nexport type WsEndpoint<TMetadata extends JsonObject> =\n    | string\n    | ((params: EndpointParams<TMetadata>) => string);\n\ntype FetchOptions = { url: string; options?: RequestInit };\n\nexport type RoomEndpoints<TIO extends IOLike<any, any, any>, TMetadata extends JsonObject> = {\n    wsEndpoint?: WsEndpoint<TMetadata>;\n} & (InferIOAuthorizeUser<InferIOAuthorize<TIO>> extends BaseUser\n    ? { authEndpoint: AuthEndpoint<TMetadata> }\n    : { authEndpoint?: undefined });\n\ninterface InternalListeners {\n    onAuthorizationFail: (error: Error) => void;\n}\n\nexport type PluvRoomAddon<\n    TIO extends IOLike,\n    TMetadata extends JsonObject,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n> = (input: PluvRoomAddonInput<TIO, TMetadata, TPresence, TCrdt>) => Partial<PluvRoomAddonResult>;\n\nexport interface PluvRoomAddonInput<\n    TIO extends IOLike,\n    TMetadata extends JsonObject,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n> {\n    room: PluvRoom<TIO, TMetadata, TPresence, TCrdt>;\n}\n\nexport interface PluvRoomAddonResult {\n    storage: AbstractStorageStore;\n}\n\nexport type PluvRoomDebug<TIO extends IOLike> = Id<{\n    output: readonly (keyof InferIOOutput<TIO>)[];\n    input: readonly (keyof InferIOInput<TIO>)[];\n}>;\n\ntype GetPublickKeyParams<TMetadata extends JsonObject = {}> = WithMetadata<TMetadata>;\ntype GetAuthEndpointParams<TMetadata extends JsonObject = {}> = WithMetadata<TMetadata>;\ntype GetWsEndpointParams<TMetadata extends JsonObject = {}> = WithMetadata<TMetadata>;\n\nexport type RoomConnectParams<TMetadata extends JsonObject = {}> = keyof TMetadata extends never\n    ? []\n    : [WithMetadata<TMetadata>];\n\nexport interface ReconnectTimeoutMsParams {\n    attempts: number;\n}\nexport type ReconnectTimeoutMs = number | ((params: ReconnectTimeoutMsParams) => number);\n\nexport type RoomConfig<\n    TIO extends IOLike,\n    TMetadata extends JsonObject,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>>,\n> = Id<\n    {\n        addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TCrdt>[];\n        debug?: boolean | PluvRoomDebug<TIO>;\n        limits: PluvClientLimits;\n        onAuthorizationFail?: (error: Error) => void;\n        metadata?: InputZodLike<TMetadata>;\n        publicKey?: PublicKey<TMetadata>;\n        reconnectTimeoutMs?: ReconnectTimeoutMs;\n        router?: PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n    } & RoomEndpoints<TIO, TMetadata> &\n        Pick<CrdtManagerOptions<TCrdt>, \"initialStorage\"> &\n        UsersManagerConfig<TPresence>\n>;\n\nexport class PluvRoom<\n    TIO extends IOLike<any, any, any>,\n    TMetadata extends JsonObject = {},\n    TPresence extends Record<string, any> = {},\n    TCrdt extends AbstractCrdtDocFactory<any, any> = NoopCrdtDocFactory,\n    TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>> = {},\n> implements RoomLike<TIO, InferDoc<TCrdt>, TPresence, InferStorage<TCrdt>> {\n    readonly _endpoints: RoomEndpoints<TIO, TMetadata>;\n\n    public readonly id: string;\n    public readonly metadata?: InputZodLike<TMetadata>;\n\n    private readonly _crdtManager: CrdtManager<TCrdt>;\n    private readonly _crdtNotifier = new CrdtNotifier<InferStorage<TCrdt>>();\n    private readonly _debug: boolean | PluvRoomDebug<TIO>;\n    private readonly _eventNotifier = new EventNotifier<MergeEvents<TEvents, TIO>>();\n    private readonly _intervals: IntervalIds = {\n        heartbeat: null,\n    };\n    private readonly _limits: PluvClientLimits;\n    private readonly _listenerManager = new ListenerManager();\n    private readonly _listeners: InternalListeners;\n    private readonly _publicKey: PublicKey<TMetadata> | null = null;\n    private readonly _reconnectTimeoutMs: ReconnectTimeoutMs;\n    private readonly _router: PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n    private readonly _stateNotifier = new StateNotifier<TIO, TPresence>();\n    private readonly _storageStore: AbstractStorageStore;\n    private readonly _subscriptions: InternalSubscriptions = {\n        observeCrdt: null,\n    };\n    private readonly _timeouts: TimeoutIds = {\n        pong: null,\n        reconnect: null,\n    };\n    private readonly _usersManager: UsersManager<TIO, TPresence>;\n    private readonly _usersNotifier = new UsersNotifier<TIO, TPresence>();\n\n    private _lastMetadata: TMetadata | null = null;\n    private _state: WebSocketState<TIO> = {\n        authorization: {\n            token: null,\n            user: null,\n        },\n        connection: {\n            attempts: 0,\n            id: null,\n            state: ConnectionState.Untouched,\n        },\n        storage: {\n            state: StorageState.Unavailable,\n        },\n        webSocket: null,\n    };\n    private _windowListeners: WindowListeners | null = null;\n    private _wsListeners: WebSocketListeners | null = null;\n\n    constructor(room: string, options: RoomConfig<TIO, TMetadata, TPresence, TCrdt, TEvents>) {\n        const {\n            addons = [],\n            authEndpoint,\n            debug = false,\n            initialPresence,\n            initialStorage,\n            limits,\n            metadata,\n            onAuthorizationFail,\n            presence,\n            publicKey,\n            reconnectTimeoutMs = RECONNECT_TIMEOUT_MS,\n            router,\n            wsEndpoint,\n        } = options;\n\n        this.id = room;\n        this.metadata = metadata;\n\n        const addon = this._getAddon(addons);\n        const { storage } = {\n            ...DEFAULT_PLUV_CLIENT_ADDON({ room: this }),\n            ...addon({ room: this }),\n        };\n        this._storageStore = storage;\n\n        this._debug = debug;\n        this._endpoints = { authEndpoint, wsEndpoint } as RoomEndpoints<TIO, TMetadata>;\n        this._limits = limits;\n        this._reconnectTimeoutMs = reconnectTimeoutMs;\n\n        if (!!publicKey) this._publicKey = publicKey;\n\n        this._listeners = {\n            onAuthorizationFail: (error) => {\n                onAuthorizationFail?.(error);\n            },\n        };\n\n        this._router =\n            router ??\n            (new PluvRouter({}) as PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>);\n        this._usersManager = new UsersManager<TIO, TPresence>({\n            initialPresence,\n            limits: this._limits,\n            presence,\n        });\n        this._crdtManager = new CrdtManager<TCrdt>({ initialStorage });\n    }\n\n    public get webSocket(): WebSocket | null {\n        return this._state.webSocket;\n    }\n\n    public addEventListener<TKind extends keyof RoomEventListenerMap>(\n        kind: TKind,\n        handler: RoomEventListenerMap[TKind],\n    ): () => void {\n        return this._listenerManager.subscribe(kind, handler as any);\n    }\n\n    public broadcast = new Proxy(\n        async <TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(\n            event: TEvent,\n            data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,\n        ): Promise<void> => {\n            if (!this._state.webSocket) return;\n            if (this._state.connection.state !== ConnectionState.Open) return;\n\n            const type = event.toString();\n\n            const procedure = this._router._defs.events[type] as PluvProcedure<\n                TIO,\n                any,\n                any,\n                TPresence,\n                TCrdt,\n                \"\"\n            > | null;\n\n            if (!procedure?.config.broadcast) {\n                this._sendMessage({ data, type });\n\n                return;\n            }\n\n            const myself = this._usersManager.myself;\n\n            if (!myself) return;\n\n            const parsed = procedure.config.input ? procedure.config.input.parse(data) : data;\n            const context: EventResolverContext<TIO, TPresence, InferDocLike<TCrdt>> = {\n                doc: this._crdtManager.doc,\n                others: this._usersManager.getOthers(),\n                room: this.id,\n                user: myself,\n            };\n\n            const output = await (\n                procedure.config.broadcast as EventResolver<\n                    TIO,\n                    any,\n                    any,\n                    TPresence,\n                    InferStorage<TCrdt>\n                >\n            )(parsed, context);\n\n            Object.entries(output).forEach(([_type, _data]) => {\n                this._sendMessage({ data: _data, type: _type });\n            });\n        },\n        {\n            get(fn, prop) {\n                return async (\n                    data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[any]>,\n                ): Promise<void> => {\n                    return await fn(prop, data);\n                };\n            },\n        },\n    ) as BroadcastProxy<TIO, TEvents>;\n\n    public canRedo = (): boolean => {\n        return !!this._crdtManager.doc.canRedo();\n    };\n\n    public canUndo = (): boolean => {\n        return !!this._crdtManager.doc.canUndo();\n    };\n\n    public async connect(...args: RoomConnectParams<TMetadata>): Promise<void> {\n        const params = (args[0] ?? {}) as WithMetadata<TMetadata>;\n        const metadata = params.metadata as TMetadata;\n\n        this._setMetadata(metadata);\n\n        const canConnect = [\n            ConnectionState.Closed,\n            ConnectionState.Unavailable,\n            ConnectionState.Untouched,\n        ].some((state) => this._state.connection.state === state);\n\n        if (!canConnect) return;\n\n        this._clearTimeout(this._timeouts.reconnect);\n        this._updateState((oldState) => {\n            oldState.connection.state = ConnectionState.Connecting;\n\n            return oldState;\n        });\n\n        await this._storageStore.initialize();\n\n        const wsEndpoint = this._getWsEndpoint(this.id, params);\n        const url = new URL(wsEndpoint);\n\n        let authToken: string | null = null;\n        let webSocket: WebSocket;\n\n        try {\n            const publicKey = this._getPublicKey(params);\n\n            authToken = await this._getAuthorization(this.id, params);\n\n            if (authToken) url.searchParams.set(\"token\", encodeURIComponent(authToken));\n            if (publicKey) url.searchParams.set(\"public_key\", encodeURIComponent(publicKey));\n\n            webSocket = new WebSocket(url.toString());\n        } catch (err) {\n            this._updateState((oldState) => {\n                oldState.connection.attempts += 1;\n\n                return oldState;\n            });\n\n            await this._storageStore.destroy();\n            this._pollReconnect();\n            await Promise.resolve(this._onAuthorizationFail(err));\n\n            return;\n        }\n\n        this._updateState((oldState) => {\n            oldState.connection.attempts = 0;\n            oldState.authorization.token = authToken;\n            oldState.storage.state = StorageState.Loading;\n            oldState.webSocket = webSocket;\n\n            return oldState;\n        });\n\n        this._attachWindowListeners();\n        this._attachWsListeners();\n    }\n\n    public async disconnect(): Promise<void> {\n        if (!this._state.webSocket) return;\n\n        const canDisconnect = [ConnectionState.Connecting, ConnectionState.Open].some(\n            (state) => this._state.connection.state === state,\n        );\n\n        if (!canDisconnect) return;\n\n        this._closeWs();\n        this._clearInterval(this._intervals.heartbeat);\n        this._clearTimeout(this._timeouts.reconnect);\n        this._updateState((oldState) => {\n            oldState.authorization.token = null;\n            oldState.connection.state = ConnectionState.Closed;\n            oldState.storage.state =\n                oldState.storage.state === StorageState.Synced\n                    ? StorageState.Offline\n                    : StorageState.Unavailable;\n            oldState.webSocket = null;\n\n            return oldState;\n        });\n\n        await this._storageStore.destroy();\n        this._crdtManager.destroy();\n        this._stateNotifier.subjects[\"my-presence\"].next(null);\n    }\n\n    public getConnection = (): WebSocketConnection => {\n        // Create a read-only clone of the connection state\n        return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));\n    };\n\n    public getDoc = (): CrdtDocLike<InferDoc<TCrdt>, InferStorage<TCrdt>> => {\n        return this._crdtManager.doc;\n    };\n\n    public getMyPresence = (): TPresence => {\n        return this._usersManager.myPresence;\n    };\n\n    public getMyself = (): Id<UserInfo<TIO, TPresence>> | null => {\n        return this._usersManager.myself;\n    };\n\n    public getOther = (connectionId: string): Id<UserInfo<TIO, TPresence>> | null => {\n        return this._usersManager.getOther(connectionId);\n    };\n\n    public getOthers = (): readonly Id<UserInfo<TIO, TPresence>>[] => {\n        return this._usersManager.getOthers();\n    };\n\n    public getStorage = <TKey extends keyof InferStorage<TCrdt>>(\n        type: TKey,\n    ): InferStorage<TCrdt>[TKey] | null => {\n        const sharedType = this._crdtManager.get(type);\n\n        if (typeof sharedType === \"undefined\") return null;\n\n        return sharedType;\n    };\n\n    public getStorageJson(): InferCrdtJson<InferStorage<TCrdt>> | null;\n    public getStorageJson<TKey extends keyof InferStorage<TCrdt>>(\n        type: TKey,\n    ): InferCrdtJson<InferStorage<TCrdt>[TKey]> | null;\n    public getStorageJson<TKey extends keyof InferStorage<TCrdt>>(type?: TKey) {\n        if (this._state.connection.id === null) return null;\n        if (typeof type === \"undefined\") return this._crdtManager.doc.toJson();\n\n        const sharedType = this._crdtManager.get(type);\n\n        if (typeof sharedType === \"undefined\") return null;\n\n        return this._crdtManager.doc.toJson(type);\n    }\n\n    public getStorageLoaded = (): boolean => {\n        return (\n            this._state.storage.state === StorageState.Offline ||\n            this._state.storage.state === StorageState.Synced\n        );\n    };\n\n    public redo = (): void => {\n        this._crdtManager.doc.redo();\n    };\n\n    public subscribe = new Proxy(\n        <TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(\n            name: TSubject,\n            callback: SubscriptionCallback<TIO, TPresence, TSubject>,\n        ): (() => void) => this._stateNotifier.subscribe(name, callback),\n        {\n            get: (fn, prop) => {\n                if (prop === \"connection\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"connection\">) => {\n                        return fn(\"connection\", callback);\n                    };\n                }\n\n                if (prop === \"myPresence\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"my-presence\">) => {\n                        return fn(\"my-presence\", callback);\n                    };\n                }\n\n                if (prop === \"myself\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"myself\">) => {\n                        return fn(\"myself\", callback);\n                    };\n                }\n\n                if (prop === \"others\") {\n                    return (callback: OthersSubscriptionCallback<TIO, TPresence>) => {\n                        return this._usersNotifier.subscribeOthers(callback);\n                    };\n                }\n\n                if (prop === \"storageLoaded\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"storage-loaded\">) => {\n                        return fn(\"storage-loaded\", callback);\n                    };\n                }\n\n                if (prop === \"event\") return this._event;\n                if (prop === \"other\") return this._other;\n                if (prop === \"storage\") return this.#_storage;\n            },\n        },\n    ) as SubscribeProxy<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n\n    public transact = (fn: (storage: InferStorage<TCrdt>) => void, origin?: string): void => {\n        const _origin = origin ?? this._state.connection.id;\n\n        /**\n         * !HACK\n         * @description Don't transact anything if there is no origin, because\n         * that means the user isn't connected yet. This will mean events are\n         * lost unfortunately.\n         * @date September 23, 2023\n         */\n        if (typeof _origin !== \"string\") return;\n\n        this._crdtManager.doc.transact(() => {\n            const storage = this._crdtManager.doc.get();\n\n            fn(storage);\n        }, _origin);\n    };\n\n    public undo = (): void => {\n        this._crdtManager.doc.undo();\n    };\n\n    public updateMyPresence = (presence: UpdateMyPresenceAction<TPresence>): void => {\n        const newPresence =\n            typeof presence === \"function\" ? presence(this.getMyPresence()) : presence;\n\n        this._usersManager.updateMyPresence(newPresence);\n\n        const myPresence = this._usersManager.myPresence;\n        const myself = this._usersManager.myself ?? null;\n\n        this._stateNotifier.subjects[\"my-presence\"].next(myPresence);\n        if (!!myself) this._stateNotifier.subjects.myself.next(myself);\n\n        this.broadcast(\n            \"$updatePresence\" as keyof InferIOInput<MergeEvents<TEvents, TIO>>,\n            { presence: newPresence } as any,\n        );\n    };\n\n    private async _addToStorageStore(update: string): Promise<void> {\n        await this._storageStore.addUpdate(update);\n\n        this._flattenStorageStore();\n    }\n\n    private _attachWindowListeners(): void {\n        if (typeof window === \"undefined\") return;\n        if (typeof document === \"undefined\") return;\n\n        this._windowListeners = this._windowListeners || {\n            onNavigatorOffline: this._onNavigatorOffline.bind(this),\n            onNavigatorOnline: this._onNavigatorOnline.bind(this),\n            onVisibilityChange: this._onVisibilityChange.bind(this),\n            onWindowFocus: this._onWindowFocus.bind(this),\n        };\n\n        window.addEventListener(\"offline\", this._windowListeners.onNavigatorOffline);\n        window.addEventListener(\"online\", this._windowListeners.onNavigatorOnline);\n        document.addEventListener(\"visibilitychange\", this._windowListeners.onVisibilityChange);\n        window.addEventListener(\"focus\", this._windowListeners.onWindowFocus);\n    }\n\n    private _attachWsListeners(): void {\n        if (!this._state.webSocket) return;\n\n        this._wsListeners = this._wsListeners || {\n            onClose: this._onClose.bind(this),\n            onError: this._onError.bind(this),\n            onMessage: this._onMessage.bind(this),\n            onOpen: this._onOpen.bind(this),\n        };\n\n        this._state.webSocket.addEventListener(\"close\", this._wsListeners.onClose);\n        this._state.webSocket.addEventListener(\"error\", this._wsListeners.onError);\n        this._state.webSocket.addEventListener(\"message\", this._wsListeners.onMessage);\n        this._state.webSocket.addEventListener(\"open\", this._wsListeners.onOpen);\n    }\n\n    private _clearInterval(interval: number | null) {\n        if (Number.isNaN(interval)) return;\n\n        clearInterval(interval as number);\n    }\n\n    private _clearTimeout(timeout: number | null) {\n        if (Number.isNaN(timeout)) return;\n\n        clearTimeout(timeout as number);\n    }\n\n    private _closeWs(): void {\n        this._subscriptions.observeCrdt?.();\n\n        this._clearInterval(this._intervals.heartbeat);\n        this._clearTimeout(this._timeouts.pong);\n        this._detachWindowListeners();\n        this._usersManager.removeMyself();\n        this._usersManager.clearConnections();\n        this._usersNotifier.clear();\n        this._stateNotifier.subjects.myself.next(null);\n        this._stateNotifier.subjects.others.next([]);\n        this._usersNotifier.others.next({ others: [], event: { kind: \"clear\" } });\n        this._state.webSocket?.close();\n\n        this._detachWsListeners();\n    }\n\n    private _detachWindowListeners(): void {\n        if (!this._windowListeners) return;\n        if (typeof window === \"undefined\") return;\n        if (typeof document === \"undefined\") return;\n\n        window.removeEventListener(\"offline\", this._windowListeners.onNavigatorOffline);\n        window.removeEventListener(\"online\", this._windowListeners.onNavigatorOnline);\n        document.removeEventListener(\"visibilitychange\", this._windowListeners.onVisibilityChange);\n        window.removeEventListener(\"focus\", this._windowListeners.onWindowFocus);\n\n        this._windowListeners = null;\n    }\n\n    private _detachWsListeners(): void {\n        if (!this._state.webSocket || !this._wsListeners) return;\n\n        this._state.webSocket.removeEventListener(\"close\", this._wsListeners.onClose);\n        this._state.webSocket.removeEventListener(\"error\", this._wsListeners.onError);\n        this._state.webSocket.removeEventListener(\"message\", this._wsListeners.onMessage);\n        this._state.webSocket.removeEventListener(\"open\", this._wsListeners.onOpen);\n\n        this._wsListeners = null;\n    }\n\n    private _emitSharedTypes(): void {\n        const sharedTypes = this._crdtManager.doc.get();\n\n        const storageRoot = Object.keys(sharedTypes).reduce(\n            (acc, prop) => {\n                const serialized = this._crdtManager.doc.toJson(prop);\n\n                this._crdtNotifier.subject(prop).next(serialized);\n\n                return { ...acc, [prop]: serialized };\n            },\n            {} as { [P in keyof InferStorage<TCrdt>]: InferCrdtJson<InferStorage<TCrdt>[P]> },\n        );\n\n        this._crdtNotifier.rootSubject.next(storageRoot);\n    }\n\n    private _event = new Proxy(\n        <TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(\n            event: TEvent,\n            callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, any>,\n        ): (() => void) => this._eventNotifier.subscribe(event, callback),\n        {\n            get(fn, prop) {\n                return (\n                    callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, any>,\n                ): (() => void) => fn(prop as any, callback);\n            },\n        },\n    ) as EventProxy<TIO, TEvents>;\n\n    private _flattenStorageStore = debounce(\n        async (): Promise<void> => {\n            const shouldFlatten = await this._storageStore.getShouldFlatten();\n\n            if (!shouldFlatten) return;\n\n            const updates = await this._storageStore.getUpdates();\n\n            this._crdtManager.applyUpdate({ update: updates, origin: this });\n\n            const encodedState = this._crdtManager.doc.getEncodedState();\n\n            await this._storageStore.flatten(encodedState);\n        },\n        { wait: ADD_TO_STORAGE_STATE_DEBOUNCE_MS },\n    );\n\n    private _getAddon = (\n        addons: readonly PluvRoomAddon<TIO, TMetadata, TPresence, TCrdt>[],\n    ): PluvRoomAddon<TIO, TMetadata, TPresence, TCrdt> => {\n        return addons.reduce<PluvRoomAddon<TIO, TMetadata, TPresence, TCrdt>>(\n            (acc, addon) => () => ({\n                ...acc({ room: this }),\n                ...addon({ room: this }),\n            }),\n            DEFAULT_PLUV_CLIENT_ADDON,\n        );\n    };\n\n    private _getAuthFetchOptions(\n        room: string,\n        params: GetAuthEndpointParams<TMetadata>,\n    ): FetchOptions | null {\n        const metadata = params.metadata as TMetadata;\n\n        if (typeof this._endpoints.authEndpoint === \"undefined\") return null;\n\n        if (this._endpoints.authEndpoint === true) {\n            return {\n                url: `/api/pluv/authorize?room=${room}`,\n                options: {},\n            };\n        }\n\n        if (typeof this._endpoints.authEndpoint === \"string\") {\n            return {\n                url: this._endpoints.authEndpoint,\n                options: {},\n            };\n        }\n\n        const result = this._endpoints.authEndpoint({ metadata, room });\n\n        return typeof result === \"string\" ? { url: result, options: {} } : result;\n    }\n\n    private async _getAuthorization(\n        room: string,\n        params: GetAuthEndpointParams<TMetadata>,\n    ): Promise<string | null> {\n        const fetchOptions = this._getAuthFetchOptions(room, params);\n\n        if (!fetchOptions) return null;\n\n        const { url, options } = fetchOptions;\n        const res = await fetch(url, options);\n\n        if (!res.ok || res.status !== 200) throw new Error(\"Room is unauthorized\");\n\n        try {\n            return await res.text().then((text) => text.trim());\n        } catch (err) {\n            throw new Error(err instanceof Error ? err.message : \"Room is unauthorized\", {\n                cause: err,\n            });\n        }\n    }\n\n    private _getPublicKey(params: GetPublickKeyParams<TMetadata>): string | null {\n        const metadata = params.metadata as TMetadata;\n\n        if (!this._publicKey) return null;\n        if (typeof this._publicKey === \"string\") return this._publicKey;\n\n        return this._publicKey({ metadata });\n    }\n\n    private _getWsEndpoint(room: string, params: GetWsEndpointParams<TMetadata>): string {\n        const metadata = params.metadata as TMetadata;\n\n        switch (typeof this._endpoints.wsEndpoint) {\n            case \"undefined\":\n                return !!this._getPublicKey(params)\n                    ? `wss://rooms.pluv.io/api/room/${room}`\n                    : `/api/pluv/room/${room}`;\n            case \"string\":\n                return this._endpoints.wsEndpoint;\n            default:\n                return this._endpoints.wsEndpoint({ metadata, room });\n        }\n    }\n\n    private _handleExit(message: IOEventMessage<TIO>): void {\n        const { connectionId } = message;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n\n        const clientId = this._usersManager.getClientId(connectionId);\n        const deleted = this._usersManager.deleteConnection(connectionId);\n        const others = this._usersManager.getOthers();\n\n        this._stateNotifier.subjects.others.next(others);\n\n        // Should not reach here\n        if (!deleted) {\n            console.warn(\"Could not identify exited connection\");\n            return;\n        }\n\n        const { data: user, remaining } = deleted;\n\n        this._usersNotifier.others.next({\n            others,\n            event: { kind: \"leave\", user },\n        });\n\n        /**\n         * @description A single user can have multiple connections. So we're checking that\n         * there isn't a remaining connection before choosing to delete that user for other\n         * connected participants.\n         * @date April 16, 2025\n         */\n        if (!remaining && !!clientId) this._usersNotifier.delete(clientId);\n    }\n\n    private _handlePresenceUpdatedMessage(message: IOEventMessage<TIO>): void {\n        const { connectionId } = message;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n\n        const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[\"$presenceUpdated\"];\n        const myself = this._usersManager.myself ?? null;\n\n        /**\n         * !HACK\n         * @description We're going to have the user's own presence be patched only via local calls\n         * to this.updateMyPresence. So we'll not update the user's presence in this handler to\n         * avoid weird update delays to the user's own presence.\n         *\n         * However, we will patch the user's own presence if the user has updated their own\n         * presence via another connection that is not this one (e.g. if the user has opened\n         * another connection in another browser tab/window somewhere).\n         * @date April 2, 2025\n         */\n        if (myself?.connectionId === connectionId) return;\n\n        const updated = this._usersManager.patchPresence(connectionId, data.presence as TPresence);\n        const myClientId = !!myself ? this._usersManager.getClientId(myself) : null;\n        const clientId = this._usersManager.getClientId(connectionId);\n\n        if (!!clientId && myClientId === clientId) {\n            this._stateNotifier.subjects[\"my-presence\"].next(updated);\n            this._stateNotifier.subjects.myself.next(this._usersManager.myself);\n\n            return;\n        }\n\n        if (!!clientId) {\n            const other = this._usersManager.getOther(connectionId);\n            const others = this._usersManager.getOthers();\n\n            this._usersNotifier.other(clientId).next(other);\n            this._stateNotifier.subjects.others.next(others);\n\n            if (!!other) {\n                this._usersNotifier.others.next({\n                    others,\n                    event: { kind: \"update\", user: other },\n                });\n            }\n\n            return;\n        }\n\n        /**\n         * !HACK\n         * @description User could not be found. Add the connection to keep others up-to-date\n         * @date April 19, 2025\n         */\n        const added = this._usersManager.addConnection({\n            connectionId,\n            presence: data.presence as TPresence,\n            user: message.user as Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>,\n        });\n        const other = this._usersManager.getOther(connectionId);\n        const others = this._usersManager.getOthers();\n\n        this._usersNotifier.other(added.clientId).next(other);\n        this._stateNotifier.subjects.others.next(others);\n\n        this._usersNotifier.others.next({\n            others,\n            event: { kind: \"update\", user: added.data },\n        });\n    }\n\n    private _handleReceiveOthers(message: IOEventMessage<TIO>): void {\n        if (!message.connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n\n        const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[\"$othersReceived\"];\n\n        Object.keys(data.others).forEach((connectionId) => {\n            const { presence, user } = data.others[connectionId];\n\n            const result = this._usersManager.addConnection({\n                connectionId,\n                presence: presence as TPresence,\n                user,\n            });\n\n            if (!!presence) this._usersManager.patchPresence(connectionId, presence as TPresence);\n            if (result.isMyself) return;\n\n            const clientId = result.clientId;\n            const other = this._usersManager.getOther(connectionId);\n\n            this._usersNotifier.other(clientId).next(other);\n        });\n\n        const others = this._usersManager.getOthers();\n\n        this._stateNotifier.subjects.others.next(others);\n        this._usersNotifier.others.next({\n            others,\n            event: { kind: \"sync\", users: others },\n        });\n    }\n\n    private async _handleRegisteredMessage(message: IOEventMessage<TIO>): Promise<void> {\n        const { connectionId } = message;\n        const user = message.user as Id<InferIOAuthorizeUser<InferIOAuthorize<TIO>>>;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n\n        const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[\"$registered\"];\n        const state = data.state;\n\n        this._updateState((oldState) => {\n            oldState.connection.id = connectionId;\n            oldState.authorization.user = user ?? null;\n\n            return oldState;\n        });\n\n        const userInfo: OptionalProps<UserInfo<TIO, TPresence>, \"presence\"> = {\n            connectionId,\n            presence: (data.presence as TPresence | null) ?? undefined,\n            user,\n        };\n        this._usersManager.setMyself(userInfo);\n\n        const presence = this._usersManager.myPresence;\n        const myself = this._usersManager.myself ?? null;\n\n        this._stateNotifier.subjects[\"my-presence\"].next(presence);\n        this._stateNotifier.subjects.myself.next(myself);\n\n        const update = await (async () => {\n            if (!!state) {\n                this._logDebug(\"Retrieving initial state\");\n                return this._crdtManager.getInitialState();\n            }\n\n            const resolved = this._crdtManager.resolveEncodedState(\n                await this._storageStore.getUpdates(),\n            );\n\n            if (!!resolved) {\n                this._logDebug(\"Retrieving storage store state\");\n                return resolved;\n            }\n\n            this._logDebug(\"Retrieving initial state\");\n            return this._crdtManager.getInitialState();\n        })();\n\n        this._sendMessage({\n            type: \"$initializeSession\",\n            data: { presence, update },\n        });\n    }\n\n    private async _handleStorageReceivedMessage(message: IOEventMessage<TIO>): Promise<void> {\n        const { connectionId } = message;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n\n        const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[\"$storageReceived\"];\n        const changeKind = data.changeKind;\n        const state = data.state;\n\n        const updates = await this._storageStore.getUpdates();\n        const origin = ORIGIN_INITIALIZED;\n\n        const updateStorage = (update: string | readonly string[]) => {\n            return this._crdtManager.initialized\n                ? this._crdtManager.applyUpdate({ update, origin })\n                : this._crdtManager.initialize({ update, origin });\n        };\n\n        if (changeKind === \"empty\") {\n            this._crdtManager.destroy();\n            this._crdtManager.initialize({ origin, update: updates });\n        } else if (changeKind === \"initialized\") {\n            if (!!updates.length) updateStorage(updates);\n            else {\n                const encodedState = updateStorage(state).doc.getEncodedState();\n\n                this._addToStorageStore(encodedState);\n            }\n        } else {\n            const encodedState = updateStorage(state).doc.getEncodedState();\n\n            if (!!updates.length) this._crdtManager.applyUpdate({ update: updates, origin });\n\n            await this._addToStorageStore(encodedState);\n        }\n\n        const encodedState = this._crdtManager.doc.getEncodedState();\n\n        this._emitSharedTypes();\n        this._observeCrdt();\n        this._updateState((oldState) => {\n            oldState.storage.state = StorageState.Synced;\n\n            return oldState;\n        });\n        this._stateNotifier.subjects[\"storage-loaded\"].next(true);\n\n        this._sendMessage({\n            type: \"$updateStorage\",\n            data: { origin, update: encodedState },\n        });\n    }\n\n    private _handleStorageUpdatedMessage(message: IOEventMessage<TIO>): void {\n        const { connectionId } = message;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n\n        const data = message.data as BaseIOEventRecord<\n            InferIOAuthorize<TIO>\n        >[typeof ORIGIN_STORAGE_UPDATED];\n\n        this._crdtManager.doc.applyEncodedState({\n            origin: ORIGIN_STORAGE_UPDATED,\n            update: data.state,\n        });\n\n        const sharedTypes = this._crdtManager.doc.get();\n\n        const storageRoot = Object.keys(sharedTypes).reduce(\n            (acc, prop) => {\n                const serialized = this._crdtManager.doc.toJson(prop);\n\n                this._crdtNotifier.subject(prop).next(serialized);\n\n                return { ...acc, [prop]: serialized };\n            },\n            {} as {\n                [P in keyof InferStorage<TCrdt>]: InferCrdtJson<InferStorage<TCrdt>[P]>;\n            },\n        );\n\n        this._crdtNotifier.rootSubject.next(storageRoot);\n    }\n\n    private _handleSyncStateReceived(message: IOEventMessage<TIO>): void {\n        const { connectionId } = message;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n        if (!this._usersManager.myself) return;\n\n        const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[\"$syncStateReceived\"];\n        const active = new Set(data?.connectionIds ?? []);\n\n        const quitters = this._usersManager\n            .getOthers()\n            .filter((other) => !active.has(other.connectionId));\n\n        quitters.forEach((quitter) => {\n            this._usersManager.deleteConnection(quitter.connectionId);\n\n            const remaining = this._usersManager.getOthers();\n\n            this._usersNotifier.others.next({\n                others: remaining,\n                event: { kind: \"leave\", user: quitter },\n            });\n        });\n\n        const remaining = this._usersManager.getOthers();\n\n        this._stateNotifier.subjects.others.next(remaining);\n    }\n\n    private _handleUserJoinedMessage(message: IOEventMessage<TIO>): void {\n        const { connectionId } = message;\n\n        if (!connectionId) return;\n        // Should not reach here\n        if (!this._state.webSocket) throw new Error(\"Could not find WebSocket\");\n        if (!this._usersManager.myself) return;\n\n        const data = message.data as BaseIOEventRecord<InferIOAuthorize<TIO>>[\"$userJoined\"];\n        const myself = this._usersManager.myself;\n\n        if (myself.connectionId === connectionId) {\n            this._sendMessage({ type: \"$getOthers\", data: {} });\n            return;\n        }\n\n        const added = this._usersManager.addConnection({\n            connectionId,\n            presence: data.presence as TPresence,\n            user: data.user,\n        });\n\n        const other = this._usersManager.getOther(connectionId);\n        const others = this._usersManager.getOthers();\n\n        this._usersNotifier.other(added.clientId).next(other);\n        this._stateNotifier.subjects.others.next(others);\n\n        this._usersNotifier.others.next({\n            others,\n            event: { kind: \"enter\", user: added.data },\n        });\n    }\n\n    private _heartbeat(): void {\n        this._clearTimeout(this._timeouts.pong);\n        this._timeouts.pong = setTimeout(\n            this._reconnect.bind(this),\n            PONG_TIMEOUT_MS,\n        ) as unknown as number;\n\n        /**\n         * !HACK\n         * @description Send data as a stable string so that the server can react to this in a\n         * consistent way.\n         * @date July 8, 2024\n         */\n        this._sendMessage('{\"type\":\"$ping\",\"data\":{}}');\n    }\n\n    private _logDebug(...data: any[]): void {\n        if (typeof process === \"undefined\") return;\n        if (process.env?.NODE_ENV === \"production\") return;\n        if (this._debug) console.log(...data);\n    }\n\n    private _observeCrdt(): void {\n        this._subscriptions.observeCrdt?.();\n\n        const unsubscribe = this._crdtManager.doc.subscribe((event) => {\n            const origin = event.origin ?? null;\n\n            this._emitSharedTypes();\n\n            if (origin === ORIGIN_INITIALIZED || origin === ORIGIN_STORAGE_UPDATED) {\n                return;\n            }\n\n            this._addToStorageStore(event.update);\n\n            if (!this._state.webSocket) return;\n            if (!this._state.connection.id) return;\n            if (this._state.webSocket.readyState !== WebSocket.OPEN) return;\n\n            this._sendMessage({\n                type: \"$updateStorage\",\n                data: { origin, update: event.update },\n            });\n        });\n\n        this._subscriptions.observeCrdt = unsubscribe;\n    }\n\n    private _onAuthorizationFail(error: unknown): void {\n        const authError = error instanceof Error ? error : new Error(\"Authorization failed\");\n\n        this._listeners.onAuthorizationFail(authError);\n\n        this._updateState((oldState) => {\n            oldState.connection.state = ConnectionState.Unavailable;\n            oldState.storage.state = StorageState.Unavailable;\n\n            return oldState;\n        });\n    }\n\n    private async _onClose(event: CloseEvent): Promise<void> {\n        this._listenerManager.subjects.close.next(event);\n\n        this._logDebug(\"WebSocket closed\");\n        if (!!event.reason) this._logDebug(event.reason);\n\n        const shouldRetry = [\n            // Going away: Client/server is shutting down or navigating\n            1001,\n            // Abnormal closure: Usually network error\n            1006,\n            // Internal error: may be a larger problem, but try reconnecting for now\n            1011,\n            // Service restart: Server restarted\n            1012,\n            // Try again later: server overloaded\n            1013,\n            // Bad gateway\n            1014,\n        ].some((okToRetryCode) => event.code === okToRetryCode);\n\n        this._updateState((oldState) => {\n            oldState.authorization.token = null;\n            oldState.connection.state = shouldRetry\n                ? ConnectionState.Unavailable\n                : /**\n                   * !HACK\n                   * @description Assume these are not recoverable. We're just going to mark this\n                   * as Closed to avoid reconnect attempts.\n                   * @date April 28, 2025\n                   */\n                  ConnectionState.Closed;\n            oldState.storage.state =\n                oldState.storage.state === StorageState.Synced\n                    ? StorageState.Offline\n                    : StorageState.Unavailable;\n            oldState.webSocket = null;\n\n            return oldState;\n        });\n\n        if (shouldRetry) {\n            await this._reconnect();\n            return;\n        }\n\n        this._closeWs();\n        this._clearTimeout(this._timeouts.reconnect);\n    }\n\n    /**\n     * TODO\n     * @description Handle websocket errors in a meaningful way, should they occur\n     * @date August 19, 2022\n     */\n    private _onError(event: Event): void {\n        this._listenerManager.subjects.error.next(event);\n    }\n\n    private _onMessage(event: MessageEvent<string>): void {\n        this._listenerManager.subjects.message.next(event);\n\n        const message = this._parseMessage(event);\n\n        if (!message) return;\n\n        const shouldLog =\n            typeof this._debug === \"boolean\"\n                ? this._debug\n                : this._debug.output.find((value) => value === message.type);\n\n        if (shouldLog) {\n            this._logDebug(\"WebSocket event received: \", message.type, message);\n        }\n\n        this._eventNotifier.subject(message.type as keyof InferIOOutput<TIO>).next(message as any);\n\n        switch (message.type) {\n            case \"$exit\": {\n                this._handleExit(message);\n                return;\n            }\n            case \"$othersReceived\": {\n                this._handleReceiveOthers(message);\n                return;\n            }\n            case \"$pong\": {\n                this._clearTimeout(this._timeouts.pong);\n                return;\n            }\n            case \"$presenceUpdated\": {\n                this._handlePresenceUpdatedMessage(message);\n                return;\n            }\n            case \"$registered\": {\n                this._handleRegisteredMessage(message);\n                return;\n            }\n            case \"$storageReceived\": {\n                this._handleStorageReceivedMessage(message);\n                return;\n            }\n            case \"$storageUpdated\": {\n                this._handleStorageUpdatedMessage(message);\n                return;\n            }\n            case \"$syncStateReceived\": {\n                this._handleSyncStateReceived(message);\n                return;\n            }\n            case \"$userJoined\": {\n                this._handleUserJoinedMessage(message);\n                return;\n            }\n            default:\n        }\n    }\n\n    private _onOpen(event: Event): void {\n        this._listenerManager.subjects.open.next(event);\n\n        if (this._state.connection.state !== ConnectionState.Connecting) return;\n\n        this._logDebug(\"WebSocket connected\");\n        this._updateState((oldState) => {\n            oldState.connection.state = ConnectionState.Open;\n\n            return oldState;\n        });\n\n        this._clearInterval(this._intervals.heartbeat);\n        this._intervals.heartbeat = setInterval(\n            this._heartbeat.bind(this),\n            HEARTBEAT_INTERVAL_MS,\n        ) as unknown as number;\n    }\n\n    private async _onNavigatorOffline(): Promise<void> {\n        if (this._state.connection.state === ConnectionState.Closed) return;\n\n        this._updateState((oldState) => {\n            oldState.connection.state = ConnectionState.Unavailable;\n            oldState.storage.state =\n                oldState.storage.state === StorageState.Synced\n                    ? StorageState.Offline\n                    : StorageState.Unavailable;\n\n            return oldState;\n        });\n    }\n\n    private async _onNavigatorOnline(): Promise<void> {\n        if (this._state.connection.state !== ConnectionState.Unavailable) return;\n\n        await this._reconnect();\n    }\n\n    private async _onVisibilityChange(): Promise<void> {\n        if (typeof document === \"undefined\") return;\n        if (document.visibilityState !== \"visible\") return;\n\n        switch (this._state.connection.state) {\n            case ConnectionState.Open: {\n                this._clearInterval(this._intervals.heartbeat);\n                setInterval(this._heartbeat.bind(this), HEARTBEAT_INTERVAL_MS);\n\n                return;\n            }\n            case ConnectionState.Unavailable: {\n                await this._reconnect();\n\n                return;\n            }\n            default:\n        }\n    }\n\n    private async _onWindowFocus(): Promise<void> {\n        return await this._onVisibilityChange();\n    }\n\n    private _other = (\n        connectionId: string,\n        callback: OtherSubscriptionCallback<TIO, TPresence>,\n    ): (() => void) => {\n        const clientId = this._usersManager.getClientId(connectionId);\n\n        if (!clientId) return () => undefined;\n\n        return this._usersNotifier.subscribeOther(clientId, callback);\n    };\n\n    private _parseMessage(message: { data: string | ArrayBuffer }): IOEventMessage<TIO> | null {\n        /**\n         * !HACK\n         * @description We'll only handle stringified JSONs for now\n         * @date August 9, 2022\n         */\n        if (typeof message.data !== \"string\") return null;\n\n        try {\n            const config = JSON.parse(message.data);\n\n            if (typeof config !== \"object\") return null;\n            if (typeof config.type !== \"string\") return null;\n            if (typeof config.data !== \"object\") return null;\n\n            return config as IOEventMessage<TIO>;\n        } catch {\n            return null;\n        }\n    }\n\n    private _pollReconnect(): void {\n        this._clearTimeout(this._timeouts.reconnect);\n\n        const timeoutMs =\n            typeof this._reconnectTimeoutMs === \"number\"\n                ? this._reconnectTimeoutMs\n                : this._reconnectTimeoutMs({ attempts: this._state.connection.attempts });\n        const clampedMs = Math.max(\n            Math.min(MIN_RECONNECT_TIMEOUT_MS, timeoutMs),\n            MAX_RECONNECT_TIMEOUT_MS,\n        );\n\n        this._timeouts.reconnect = setTimeout(\n            this._reconnect.bind(this),\n            clampedMs,\n        ) as unknown as number;\n    }\n\n    private async _reconnect(): Promise<void> {\n        this._closeWs();\n\n        /**\n         * @description User has manually closed this connection. We're not going to retry, since\n         * the user probably intends for this to stay closed. They will need to invoke connect\n         * themselves.\n         * @date April 28, 2025\n         */\n        if (this._state.connection.state === ConnectionState.Closed) return;\n\n        const metadata = this._lastMetadata;\n        const params = (\n            typeof metadata === \"undefined\" ? [] : [{ metadata }]\n        ) as RoomConnectParams<TMetadata>;\n\n        await this.connect(...params);\n    }\n\n    private _sendMessage(data: string): void;\n    private _sendMessage<TMessage extends EventMessage<string, any> = EventMessage<string, any>>(\n        data: TMessage,\n    ): void;\n    private _sendMessage(data: any): void {\n        const webSocket = this._state.webSocket;\n\n        if (webSocket?.readyState !== WebSocket.OPEN) return;\n\n        const dataType: string | null = ((): string | null => {\n            if (typeof data === \"object\") return data.type ?? null;\n            if (typeof data !== \"string\") return null;\n\n            try {\n                return JSON.parse(data)?.type ?? null;\n            } catch {\n                return null;\n            }\n        })();\n\n        const shouldLog: boolean =\n            typeof this._debug === \"boolean\"\n                ? this._debug\n                : !dataType\n                  ? false\n                  : this._debug.input.some((value) => value === data.type);\n\n        if (shouldLog) this._logDebug(\"WebSocket event sent: \", data.type, data);\n\n        const message = typeof data === \"string\" ? data : JSON.stringify(data);\n\n        webSocket.send(message);\n    }\n\n    private _setMetadata(metadata: TMetadata): TMetadata {\n        const parsed = this.metadata ? this.metadata.parse(metadata) : metadata;\n\n        this._lastMetadata = parsed;\n\n        return parsed;\n    }\n\n    #_storage = new Proxy(\n        <TKey extends keyof InferStorage<TCrdt>>(\n            key: TKey,\n            callback: StorageSubscriptionCallback<InferStorage<TCrdt>, TKey>,\n        ): (() => void) => this._crdtNotifier.subscribe(key, callback),\n        {\n            get: (fn, prop) => {\n                type _Storage = InferStorage<TCrdt>;\n\n                if (!!prop) {\n                    return (callback: StorageRootSubscriptionCallback<_Storage>) => {\n                        return this._crdtNotifier.subcribeRoot(callback);\n                    };\n                }\n\n                return (callback: StorageSubscriptionCallback<_Storage, keyof _Storage>) => {\n                    return fn(prop as keyof InferStorage<TCrdt>, callback);\n                };\n            },\n        },\n    ) as StorageProxy<InferStorage<TCrdt>>;\n\n    private _updateState(\n        updater: (oldState: WebSocketState<TIO>) => WebSocketState<TIO>,\n    ): WebSocketState<TIO> {\n        let authorization: AuthorizationState<TIO>;\n\n        try {\n            authorization = JSON.parse(JSON.stringify(this._state.authorization));\n        } catch {\n            throw new Error(\"User is not JSON serializable\");\n        }\n\n        const oldState: WebSocketState<TIO> = {\n            ...this._state,\n            authorization,\n            connection: JSON.parse(JSON.stringify(this._state.connection)),\n            storage: JSON.parse(JSON.stringify(this._state.storage)),\n            webSocket: this._state.webSocket,\n        };\n\n        const newState = updater(oldState);\n        this._state = newState;\n\n        this._logDebug(\"WebSocket new state: \", newState);\n        this._stateNotifier.subjects.connection.next(newState);\n\n        return newState;\n    }\n}\n","import type { AbstractCrdtDocFactory, InferStorage, NoopCrdtDocFactory } from \"@pluv/crdt\";\nimport type { InferIOCrdtKind, InputZodLike, IOLike, JsonObject } from \"@pluv/types\";\nimport { MAX_PRESENCE_SIZE_BYTES } from \"./constants\";\nimport type { InferCallback } from \"./infer\";\nimport { PluvProcedure } from \"./PluvProcedure\";\nimport type {\n    AuthEndpoint,\n    PluvRoomAddon,\n    PluvRoomDebug,\n    ReconnectTimeoutMs,\n    RoomConfig,\n    RoomEndpoints,\n    WsEndpoint,\n} from \"./PluvRoom\";\nimport { PluvRoom } from \"./PluvRoom\";\nimport type { PluvRouterEventConfig } from \"./PluvRouter\";\nimport { PluvRouter } from \"./PluvRouter\";\nimport type { PluvClientLimits, PublicKey, WithMetadata } from \"./types\";\n\nexport type PluvClientOptions<\n    TIO extends IOLike<any, any, any>,\n    TPresence extends Record<string, any>,\n    TCrdt extends InferIOCrdtKind<TIO>,\n    TMetadata extends JsonObject,\n> = RoomEndpoints<TIO, TMetadata> & {\n    debug?: boolean;\n    /**\n     * @description Configurable limits defined for client-side validation. You should only set\n     * this if you control the server and have changed the limits there.\n     */\n    limits?: PluvClientLimits;\n    metadata?: InputZodLike<TMetadata>;\n    presence?: InputZodLike<TPresence>;\n    publicKey?: PublicKey<TMetadata>;\n    types: InferCallback<TIO>;\n} & (InferIOCrdtKind<TIO> extends NoopCrdtDocFactory\n        ? { initialStorage?: \"[ERROR]: Must provide crdt to createIO to use storage\" }\n        : { initialStorage?: TCrdt });\n\nexport type CreateRoomOptions<\n    TIO extends IOLike<any, any, any>,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TMetadata extends JsonObject,\n    TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>> = {},\n> = {\n    addons?: readonly PluvRoomAddon<TIO, TMetadata, TPresence, InferStorage<TCrdt>>[];\n    debug?: boolean | PluvRoomDebug<TIO>;\n    initialPresence?: TPresence;\n    initialStorage?: TCrdt;\n    onAuthorizationFail?: (error: Error) => void;\n    reconnectTimeoutMs?: ReconnectTimeoutMs;\n    router?: PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n};\n\nexport type EnterRoomParams<TMetadata extends JsonObject = {}> = keyof TMetadata extends never\n    ? []\n    : [WithMetadata<TMetadata>];\n\nexport class PluvClient<\n    TIO extends IOLike<any, any, any>,\n    TPresence extends Record<string, any> = {},\n    TCrdt extends InferIOCrdtKind<TIO> = InferIOCrdtKind<TIO>,\n    TMetadata extends JsonObject = {},\n> {\n    public readonly metadata?: InputZodLike<TMetadata>;\n\n    private readonly _authEndpoint: AuthEndpoint<TMetadata> | undefined;\n    private readonly _debug: boolean;\n    private readonly _initialStorage?: TCrdt;\n    private readonly _limits: PluvClientLimits;\n    private readonly _presence?: InputZodLike<TPresence>;\n    private readonly _publicKey: PublicKey<TMetadata> | null = null;\n    private readonly _rooms = new Map<string, PluvRoom<TIO, TMetadata, TPresence, TCrdt, any>>();\n    private readonly _wsEndpoint: WsEndpoint<TMetadata> | undefined;\n\n    public get _defs() {\n        return {\n            initialStorage: this._initialStorage,\n        };\n    }\n\n    public get procedure(): PluvProcedure<TIO, {}, {}, TPresence, TCrdt, \"\"> {\n        return new PluvProcedure<TIO, {}, {}, TPresence, TCrdt, \"\">();\n    }\n\n    constructor(options: PluvClientOptions<TIO, TPresence, TCrdt, TMetadata>) {\n        const {\n            authEndpoint,\n            debug = false,\n            initialStorage,\n            limits,\n            metadata,\n            presence,\n            publicKey,\n            wsEndpoint,\n        } = options;\n\n        this.metadata = metadata;\n\n        this._authEndpoint = authEndpoint as AuthEndpoint<TMetadata>;\n        this._debug = debug;\n        this._initialStorage = initialStorage as TCrdt;\n        this._limits = {\n            presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,\n            ...limits,\n        };\n        this._presence = presence;\n        this._wsEndpoint = wsEndpoint;\n\n        if (!!publicKey) this._publicKey = publicKey;\n    }\n\n    public createRoom = <\n        TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>> = {},\n    >(\n        room: string,\n        options: CreateRoomOptions<TIO, TPresence, TCrdt, TMetadata, TEvents> = {},\n    ): PluvRoom<TIO, TMetadata, TPresence, TCrdt, TEvents> => {\n        const oldRoom = this.getRoom(room);\n\n        if (oldRoom) return oldRoom;\n\n        const newRoom = new PluvRoom<TIO, TMetadata, TPresence, TCrdt, TEvents>(room, {\n            addons: options.addons,\n            authEndpoint: this._authEndpoint,\n            debug: options.debug,\n            initialPresence: options.initialPresence,\n            initialStorage: options.initialStorage ?? this._initialStorage,\n            limits: this._limits,\n            metadata: this.metadata,\n            onAuthorizationFail: options.onAuthorizationFail,\n            presence: this._presence,\n            publicKey: this._publicKey ?? undefined,\n            reconnectTimeoutMs: options.reconnectTimeoutMs,\n            router: options.router,\n            wsEndpoint: this._wsEndpoint,\n        } as RoomConfig<TIO, TMetadata, TPresence, TCrdt, TEvents>);\n\n        this._rooms.set(room, newRoom);\n\n        this._logDebug(`New room was created: ${room}`);\n\n        return newRoom;\n    };\n\n    public enter = async (\n        room: string | PluvRoom<TIO, TMetadata, any, any, any>,\n        ...args: EnterRoomParams<TMetadata>\n    ): Promise<PluvRoom<TIO, TMetadata, TPresence, TCrdt, any>> => {\n        const toEnter = typeof room === \"string\" ? this.getRoom(room) : room;\n\n        if (!toEnter) throw new Error(`Could not find room: ${room}.`);\n\n        this._rooms.set(toEnter.id, toEnter);\n        await toEnter.connect(...args);\n\n        this._logDebug(`Entered room: ${room}`);\n\n        return toEnter;\n    };\n\n    public getRoom = (room: string): PluvRoom<TIO, TMetadata, TPresence, TCrdt, any> | null => {\n        const found = this._rooms.get(room) as\n            | PluvRoom<TIO, TMetadata, TPresence, TCrdt, any>\n            | undefined;\n\n        return found ?? null;\n    };\n\n    public getRooms = (): readonly PluvRoom<TIO, TMetadata, TPresence, TCrdt, any>[] => {\n        return Array.from(this._rooms.values());\n    };\n\n    public leave = async (room: string | PluvRoom<TIO, any, any, any>): Promise<void> => {\n        const toLeave = typeof room === \"string\" ? this.getRoom(room) : room;\n\n        if (!toLeave) return;\n\n        await toLeave.disconnect();\n\n        this._rooms.delete(toLeave.id);\n\n        this._logDebug(`Left and deleted room: ${room}`);\n    };\n\n    public router<TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>> = {}>(\n        events: TEvents,\n    ): PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents> {\n        const invalidName = Object.keys(events).find((name) => name.includes(\"$\"));\n\n        if (typeof invalidName === \"string\") {\n            throw new Error(`Invalid event name. Event names must not contain $: \"${invalidName}\"`);\n        }\n\n        return new PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>(events);\n    }\n\n    private _logDebug(...data: any[]): void {\n        if (typeof process === \"undefined\") return;\n        if (process.env?.NODE_ENV === \"production\") return;\n\n        if (this._debug) console.log(...data);\n    }\n}\n","import type { InferIOCrdtKind, IOLike, JsonObject } from \"@pluv/types\";\nimport type { PluvClientOptions } from \"./PluvClient\";\nimport { PluvClient } from \"./PluvClient\";\n\nexport const createClient = <\n    TIO extends IOLike<any, any, any>,\n    TPresence extends Record<string, any> = {},\n    TCrdt extends InferIOCrdtKind<TIO> = InferIOCrdtKind<TIO>,\n    TMetadata extends JsonObject = {},\n>(\n    options: PluvClientOptions<TIO, TPresence, TCrdt, TMetadata>,\n): PluvClient<TIO, TPresence, TCrdt, TMetadata> => {\n    return new PluvClient<TIO, TPresence, TCrdt, TMetadata>(options);\n};\n","import type { InferIOAuthorize, InferIOCrdt, InferIOEvents, IOLike } from \"@pluv/types\";\nimport type { identity } from \"./utils\";\n\nexport type InferCallback<TIO extends IOLike<any, any, any>> = (i: typeof identity) => {\n    io: (io: TIO) => TIO;\n};\n\nexport const infer = <TIO extends IOLike<any, any, any>>(\n    callback: InferCallback<TIO>,\n): InferCallback<IOLike<InferIOAuthorize<TIO>, InferIOCrdt<TIO>, InferIOEvents<TIO>>> => {\n    return callback as any;\n};\n","import type {\n    AbstractCrdtDocFactory,\n    InferCrdtJson,\n    InferDoc,\n    InferDocLike,\n    InferStorage,\n} from \"@pluv/crdt\";\nimport type {\n    BroadcastProxy,\n    CrdtDocLike,\n    EventNotifierSubscriptionCallback,\n    EventProxy,\n    IOLike,\n    Id,\n    InferIOInput,\n    InferIOOutput,\n    MergeEvents,\n    OtherSubscriptionCallback,\n    OthersSubscriptionCallback,\n    RoomEventListenerMap,\n    RoomLike,\n    StateNotifierSubjects,\n    StorageProxy,\n    StorageRootSubscriptionCallback,\n    StorageSubscriptionCallback,\n    SubscribeProxy,\n    SubscriptionCallback,\n    UpdateMyPresenceAction,\n    UserInfo,\n    WebSocketConnection,\n    WebSocketState,\n} from \"@pluv/types\";\nimport { ConnectionState, StorageState } from \"@pluv/types\";\nimport type { CrdtManagerOptions } from \"./CrdtManager\";\nimport { CrdtManager } from \"./CrdtManager\";\nimport { CrdtNotifier } from \"./CrdtNotifier\";\nimport { EventNotifier } from \"./EventNotifier\";\nimport { PluvProcedure } from \"./PluvProcedure\";\nimport type { PluvRouterEventConfig } from \"./PluvRouter\";\nimport { PluvRouter } from \"./PluvRouter\";\nimport { StateNotifier } from \"./StateNotifier\";\nimport type { UsersManagerConfig } from \"./UsersManager\";\nimport { UsersManager } from \"./UsersManager\";\nimport { UsersNotifier } from \"./UsersNotifier\";\nimport { MAX_PRESENCE_SIZE_BYTES } from \"./constants\";\nimport type {\n    EventResolver,\n    EventResolverContext,\n    InternalSubscriptions,\n    PluvClientLimits,\n} from \"./types\";\n\nexport type MockedRoomEvents<TIO extends IOLike> = Partial<{\n    [P in keyof InferIOInput<TIO>]: (data: Id<InferIOInput<TIO>[P]>) => Partial<InferIOOutput<TIO>>;\n}>;\n\nexport type MockedRoomConfig<\n    TIO extends IOLike,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>>,\n> = {\n    events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;\n    limits?: PluvClientLimits;\n    router?: PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n} & Pick<CrdtManagerOptions<TCrdt>, \"initialStorage\"> &\n    Omit<UsersManagerConfig<TPresence>, \"limits\">;\n\nexport class MockedRoom<\n    TIO extends IOLike,\n    TPresence extends Record<string, any>,\n    TCrdt extends AbstractCrdtDocFactory<any, any>,\n    TEvents extends PluvRouterEventConfig<TIO, TPresence, InferStorage<TCrdt>>,\n> implements RoomLike<TIO, InferDoc<TCrdt>, TPresence, InferStorage<TCrdt>> {\n    public readonly id: string;\n\n    private readonly _crdtManager: CrdtManager<TCrdt>;\n    private readonly _crdtNotifier = new CrdtNotifier<InferStorage<TCrdt>>();\n    private readonly _eventNotifier = new EventNotifier<MergeEvents<TEvents, TIO>>();\n    private readonly _events?: MockedRoomEvents<MergeEvents<TEvents, TIO>>;\n    private readonly _limits: PluvClientLimits;\n    private readonly _usersNotifier = new UsersNotifier<TIO, TPresence>();\n    private readonly _router: PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n    private _state: WebSocketState<TIO> = {\n        authorization: {\n            token: null,\n            user: null,\n        },\n        connection: {\n            attempts: 0,\n            id: null,\n            state: ConnectionState.Untouched,\n        },\n        storage: {\n            state: StorageState.Unavailable,\n        },\n        webSocket: null,\n    };\n    private readonly _stateNotifier = new StateNotifier<TIO, TPresence>();\n    private readonly _subscriptions: InternalSubscriptions = {\n        observeCrdt: null,\n    };\n    private readonly _usersManager: UsersManager<TIO, TPresence>;\n\n    constructor(room: string, options: MockedRoomConfig<TIO, TPresence, TCrdt, TEvents>) {\n        const { events, initialPresence, initialStorage, limits, presence, router } = options;\n\n        this.id = room;\n\n        this._events = events;\n        this._limits = {\n            presenceMaxSize: MAX_PRESENCE_SIZE_BYTES,\n            ...limits,\n        };\n        this._router =\n            router ??\n            (new PluvRouter({}) as PluvRouter<TIO, TPresence, InferStorage<TCrdt>, TEvents>);\n        this._usersManager = new UsersManager<TIO, TPresence>({\n            initialPresence,\n            limits: this._limits,\n            presence,\n        });\n\n        this._crdtManager = new CrdtManager<TCrdt>({\n            initialStorage,\n        });\n\n        this._observeCrdt();\n    }\n\n    public addEventListener<TKind extends keyof RoomEventListenerMap>(\n        kind: TKind,\n        handler: RoomEventListenerMap[TKind],\n    ): () => void {\n        return () => undefined;\n    }\n\n    public broadcast = new Proxy(\n        async <TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(\n            event: TEvent,\n            data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,\n        ): Promise<void> => {\n            if (!this._state.webSocket) return;\n            if (this._state.connection.state !== ConnectionState.Open) return;\n\n            const type = event.toString();\n\n            const procedure = this._router._defs.events[type] as PluvProcedure<\n                TIO,\n                any,\n                any,\n                TPresence,\n                TCrdt,\n                \"\"\n            > | null;\n\n            if (!procedure?.config.broadcast) {\n                this._simulateEvent(type as TEvent, data);\n\n                return;\n            }\n\n            const myself = this._usersManager.myself;\n\n            if (!myself) return;\n\n            const parsed = procedure.config.input ? procedure.config.input.parse(data) : data;\n            const context: EventResolverContext<TIO, TPresence, InferDocLike<TCrdt>> = {\n                doc: this._crdtManager.doc,\n                others: this._usersManager.getOthers(),\n                room: this.id,\n                user: myself,\n            };\n\n            const output = await (\n                procedure.config.broadcast as EventResolver<\n                    TIO,\n                    any,\n                    any,\n                    TPresence,\n                    InferStorage<TCrdt>\n                >\n            )(parsed, context);\n\n            Object.entries(output).forEach(([_type, _data]) => {\n                this._simulateEvent(_type as TEvent, _data as any);\n            });\n        },\n        {\n            get(fn, prop) {\n                return async (\n                    data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[any]>,\n                ): Promise<void> => {\n                    return await fn(prop, data);\n                };\n            },\n        },\n    ) as BroadcastProxy<TIO, TEvents>;\n\n    public canRedo = (): boolean => {\n        return !!this._crdtManager.doc.canRedo();\n    };\n\n    public canUndo = (): boolean => {\n        return !!this._crdtManager.doc.canUndo();\n    };\n\n    public getConnection = (): WebSocketConnection => {\n        // Create a read-only clone of the connection state\n        return Object.freeze(JSON.parse(JSON.stringify(this._state.connection)));\n    };\n\n    public getDoc(): CrdtDocLike<InferDoc<TCrdt>, InferStorage<TCrdt>> {\n        return this._crdtManager.doc;\n    }\n\n    public getMyPresence = (): TPresence => {\n        return this._usersManager.myPresence;\n    };\n\n    public getMyself = (): Id<UserInfo<TIO, TPresence>> | null => {\n        return this._usersManager.myself;\n    };\n\n    public getOther = (connectionId: string): Id<UserInfo<TIO, TPresence>> | null => {\n        return this._usersManager.getOther(connectionId);\n    };\n\n    public getOthers = (): readonly Id<UserInfo<TIO, TPresence>>[] => {\n        return this._usersManager.getOthers();\n    };\n\n    public getStorage = <TKey extends keyof InferStorage<TCrdt>>(\n        type: TKey,\n    ): InferStorage<TCrdt>[TKey] | null => {\n        const sharedType = this._crdtManager.get(type);\n\n        if (typeof sharedType === \"undefined\") return null;\n\n        return sharedType;\n    };\n\n    public getStorageJson(): InferCrdtJson<InferStorage<TCrdt>> | null;\n    public getStorageJson<TKey extends keyof InferStorage<TCrdt>>(\n        type: TKey,\n    ): InferCrdtJson<InferStorage<TCrdt>[TKey]> | null;\n    public getStorageJson<TKey extends keyof InferStorage<TCrdt>>(type?: TKey) {\n        if (this._state.connection.id === null) return null;\n        if (typeof type === \"undefined\") return this._crdtManager.doc.toJson();\n\n        return this._crdtManager.doc.toJson(type);\n    }\n\n    public getStorageLoaded(): boolean {\n        return true;\n    }\n\n    public redo = (): void => {\n        this._crdtManager.doc.redo();\n    };\n\n    public storageRoot = (\n        fn: (value: {\n            [P in keyof InferStorage<TCrdt>]: InferCrdtJson<InferStorage<TCrdt>[P]>;\n        }) => void,\n    ): (() => void) => {\n        return this._crdtNotifier.subcribeRoot(fn);\n    };\n\n    public subscribe = new Proxy(\n        <TSubject extends keyof StateNotifierSubjects<TIO, TPresence>>(\n            name: TSubject,\n            callback: SubscriptionCallback<TIO, TPresence, TSubject>,\n        ): (() => void) => {\n            return this._stateNotifier.subscribe(name, callback);\n        },\n        {\n            get: (fn, prop) => {\n                if (prop === \"connection\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"connection\">) => {\n                        return fn(\"connection\", callback);\n                    };\n                }\n\n                if (prop === \"myPresence\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"my-presence\">) => {\n                        return fn(\"my-presence\", callback);\n                    };\n                }\n\n                if (prop === \"myself\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"myself\">) => {\n                        return fn(\"myself\", callback);\n                    };\n                }\n\n                if (prop === \"others\") {\n                    return (callback: OthersSubscriptionCallback<TIO, TPresence>) => {\n                        return this._usersNotifier.subscribeOthers(callback);\n                    };\n                }\n\n                if (prop === \"storageLoaded\") {\n                    return (callback: SubscriptionCallback<TIO, TPresence, \"storage-loaded\">) => {\n                        return fn(\"storage-loaded\", callback);\n                    };\n                }\n\n                if (prop === \"event\") return this._event;\n                if (prop === \"other\") return this._other;\n                if (prop === \"storage\") return this.#_storage;\n            },\n        },\n    ) as SubscribeProxy<TIO, TPresence, InferStorage<TCrdt>, TEvents>;\n\n    public transact = (fn: (storage: InferStorage<TCrdt>) => void, origin?: string): void => {\n        const _origin = origin ?? this._state.connection.id;\n        const crdtManager = this._crdtManager;\n\n        /**\n         * !HACK\n         * @description Don't transact anything if there is no origin, because\n         * that means the user isn't connected yet. This will mean events are\n         * lost unfortunately.\n         * @date September 23, 2023\n         */\n        if (typeof _origin !== \"string\") return;\n        if (!crdtManager) return;\n\n        crdtManager.doc.transact(() => {\n            const storage = crdtManager.doc.get();\n\n            fn(storage);\n        }, _origin);\n    };\n\n    public undo = (): void => {\n        this._crdtManager.doc.undo();\n    };\n\n    public updateMyPresence = (presence: UpdateMyPresenceAction<TPresence>): void => {\n        const newPresence =\n            typeof presence === \"function\" ? presence(this.getMyPresence()) : presence;\n\n        this._usersManager.updateMyPresence(newPresence);\n\n        const myPresence = this._usersManager.myPresence;\n        const myself = this._usersManager.myself ?? null;\n\n        this._stateNotifier.subjects[\"my-presence\"].next(myPresence);\n        if (!!myself) this._stateNotifier.subjects[\"myself\"].next(myself);\n    };\n\n    private _event = new Proxy(\n        <TEvent extends keyof InferIOOutput<MergeEvents<TEvents, TIO>>>(\n            event: TEvent,\n            callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, any>,\n        ): (() => void) => this._eventNotifier.subscribe(event, callback),\n        {\n            get(fn, prop) {\n                return (\n                    callback: EventNotifierSubscriptionCallback<MergeEvents<TEvents, TIO>, any>,\n                ): (() => void) => fn(prop as any, callback);\n            },\n        },\n    ) as EventProxy<TIO, TEvents>;\n\n    private _observeCrdt(): void {\n        this._subscriptions.observeCrdt?.();\n\n        if (!this._crdtManager) return;\n\n        const unsubscribe = this._crdtManager.doc.subscribe((event) => {\n            const origin = event.origin ?? null;\n\n            if (!this._crdtManager) return;\n            if (origin === \"$storageUpdated\") return;\n\n            const sharedTypes = this._crdtManager.doc.get();\n\n            const storageRoot = Object.keys(sharedTypes).reduce(\n                (acc, prop) => {\n                    if (!this._crdtManager) return acc;\n\n                    const serialized = this._crdtManager.doc.toJson(prop);\n\n                    this._crdtNotifier.subject(prop).next(serialized);\n\n                    return { ...acc, [prop]: serialized };\n                },\n                {} as {\n                    [P in keyof InferStorage<TCrdt>]: InferCrdtJson<InferStorage<TCrdt>[P]>;\n                },\n            );\n\n            this._crdtNotifier.rootSubject.next(storageRoot);\n        });\n\n        this._subscriptions.observeCrdt = unsubscribe;\n    }\n\n    private _other = (\n        connectionId: string,\n        callback: OtherSubscriptionCallback<TIO, TPresence>,\n    ): (() => void) => {\n        const clientId = this._usersManager.getClientId(connectionId);\n\n        if (!clientId) return () => undefined;\n\n        return this._usersNotifier.subscribeOther(clientId, callback);\n    };\n\n    private _simulateEvent<TEvent extends keyof InferIOInput<MergeEvents<TEvents, TIO>>>(\n        event: TEvent,\n        data: Id<InferIOInput<MergeEvents<TEvents, TIO>>[TEvent]>,\n    ) {\n        if (!this._events) return;\n\n        const type = event.toString();\n        const resolver = this._events[type as TEvent];\n\n        if (!resolver) return;\n\n        const result = resolver(data);\n\n        Object.keys(result).forEach((type) => {\n            const _type = type.toString() as keyof Partial<InferIOOutput<TIO>>;\n            const data = result[_type] as any;\n\n            if (!data) return;\n\n            this._eventNotifier.subject(_type).next(data);\n        });\n    }\n\n    #_storage = new Proxy(\n        <TKey extends keyof InferStorage<TCrdt>>(\n            key: TKey,\n            callback: StorageSubscriptionCallback<InferStorage<TCrdt>, TKey>,\n        ): (() => void) => this._crdtNotifier.subscribe(key, callback),\n        {\n            get: (fn, prop) => {\n                type _Storage = InferStorage<TCrdt>;\n\n                if (!!prop) {\n                    return (callback: StorageRootSubscriptionCallback<_Storage>) => {\n                        return this._crdtNotifier.subcribeRoot(callback);\n                    };\n                }\n\n                return (callback: StorageSubscriptionCallback<_Storage, keyof _Storage>) => {\n                    return fn(prop as keyof InferStorage<TCrdt>, callback);\n                };\n            },\n        },\n    ) as StorageProxy<InferStorage<TCrdt>>;\n}\n","import type { JsonObject } from \"@pluv/types\";\nimport type { AuthEndpoint, WsEndpoint } from \"./PluvRoom\";\n\nexport interface RegisterParams<TMetadata extends JsonObject> {\n    authEndpoint: AuthEndpoint<TMetadata>;\n    publicKey: string;\n}\n\nexport const register = <TMetadata extends JsonObject>(params: RegisterParams<TMetadata>) => {\n    const { authEndpoint, publicKey } = params;\n\n    const wsEndpoint: WsEndpoint<TMetadata> = ({ room }) =>\n        `wss://connect.pluv.io/api/room?room=${room}`;\n\n    return {\n        authEndpoint,\n        publicKey,\n        wsEndpoint,\n    };\n};\n"],"mappings":"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"}