@liveblocks/react 3.13.3-slate1 → 3.14.0-pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_private.cjs +7 -7
- package/dist/_private.js +1 -1
- package/dist/{chunk-ZGMDUGQV.js → chunk-3R6RNKTQ.js} +2 -2
- package/dist/{chunk-ERRJHA6O.js → chunk-5C2OIBKL.js} +2 -5
- package/dist/chunk-5C2OIBKL.js.map +1 -0
- package/dist/{chunk-P6WD5XJD.cjs → chunk-I3OSF42A.cjs} +2 -2
- package/dist/{chunk-P6WD5XJD.cjs.map → chunk-I3OSF42A.cjs.map} +1 -1
- package/dist/{chunk-QFAOGFJK.cjs → chunk-RE7FR44F.cjs} +2 -5
- package/dist/chunk-RE7FR44F.cjs.map +1 -0
- package/dist/index.cjs +4 -4
- package/dist/index.js +2 -2
- package/dist/suspense.cjs +4 -4
- package/dist/suspense.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-ERRJHA6O.js.map +0 -1
- package/dist/chunk-QFAOGFJK.cjs.map +0 -1
- /package/dist/{chunk-ZGMDUGQV.js.map → chunk-3R6RNKTQ.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/contexts.ts","../src/lib/use-latest.ts","../src/ai.tsx","../src/use-sync-external-store-with-selector.ts","../src/use-signal.ts","../src/liveblocks.tsx","../src/config.ts","../src/lib/AsyncResult.ts","../src/lib/ssr.ts","../src/lib/use-initial.ts","../src/lib/use-polyfill.ts","../src/umbrella-store.ts","../src/lib/autobind.ts","../src/lib/itertools.ts","../src/lib/querying.ts","../src/ThreadDB.ts","../src/room.tsx","../src/use-scroll-to-comment-on-load-effect.ts"],"sourcesContent":["import type {\n BaseMetadata,\n BaseUserMeta,\n Client,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport type { OpaqueClient, OpaqueRoom } from \"@liveblocks/core\";\nimport { raise } from \"@liveblocks/core\";\nimport { createContext, useContext } from \"react\";\n\n/**\n * Raw access to the React context where the LiveblocksProvider stores the\n * current client. Exposed for advanced use cases only.\n *\n * @private This is a private/advanced API. Do not rely on it.\n */\nexport const ClientContext = createContext<OpaqueClient | null>(null);\n\n/**\n * @private This is an internal API.\n */\nexport function useClientOrNull<U extends BaseUserMeta>() {\n return useContext(ClientContext) as Client<U> | null;\n}\n\n/**\n * Obtains a reference to the current Liveblocks client.\n */\nexport function useClient<U extends BaseUserMeta>() {\n return (\n useClientOrNull<U>() ??\n raise(\"LiveblocksProvider is missing from the React tree.\")\n );\n}\n\n/**\n * Raw access to the React context where the RoomProvider stores the current\n * room. Exposed for advanced use cases only.\n *\n * @private This is a private/advanced API. Do not rely on it.\n */\nexport const RoomContext = createContext<OpaqueRoom | null>(null);\n\n/** @private */\nexport function useRoomOrNull<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(): Room<P, S, U, E, TM, CM> | null {\n return useContext(RoomContext) as Room<P, S, U, E, TM, CM> | null;\n}\n\n/**\n * Returns whether the hook is called within a RoomProvider context.\n *\n * @example\n * const isInsideRoom = useIsInsideRoom();\n */\nexport function useIsInsideRoom(): boolean {\n const room = useRoomOrNull();\n return room !== null;\n}\n","import type { MutableRefObject } from \"react\";\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Keeps a ref in sync with a given value that may or may not change on\n * every render.\n *\n * The purpose of this hook is to return a stable ref that can be passed\n * to a callback function so the callback can be registered but still can\n * access the latest value at a later point in time.\n */\nexport function useLatest<T>(value: T): MutableRefObject<T> {\n const ref = useRef(value);\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref;\n}\n","import type { LayerKey } from \"@liveblocks/core\";\nimport { kInternal, nanoid } from \"@liveblocks/core\";\nimport { memo, useEffect, useId, useState } from \"react\";\n\nimport { useClient } from \"./contexts\";\nimport type { RegisterAiKnowledgeProps, RegisterAiToolProps } from \"./types/ai\";\n\nfunction useAi() {\n return useClient()[kInternal].ai;\n}\n\nfunction useRandom() {\n return useState(nanoid)[0];\n}\n\n/**\n * Make knowledge about your application state available to any AI used in\n * a chat or a one-off request.\n *\n * For example:\n *\n * <RegisterAiKnowledge\n * description=\"The current mode of my application\"\n * value=\"dark\" />\n *\n * Or scoped to a specific chat:\n *\n * <RegisterAiKnowledge\n * description=\"The current list of todos\"\n * value={todos}\n * chatId=\"chat-1234\" />\n *\n * By mounting this component, the AI will get access to this knwoledge.\n * By unmounting this component, the AI will no longer have access to it.\n * It can choose to use or ignore this knowledge in its responses.\n */\nexport const RegisterAiKnowledge = memo(function RegisterAiKnowledge(\n props: RegisterAiKnowledgeProps\n) {\n const layerId = useId();\n const ai = useAi();\n const { description, value, chatId } = props;\n\n const [layerKey, setLayerKey] = useState<LayerKey | undefined>();\n\n // Executes at mount / unmount\n useEffect(() => {\n const { layerKey, deregister } = ai.registerKnowledgeLayer(layerId, chatId);\n setLayerKey(layerKey);\n return () => {\n deregister();\n setLayerKey(undefined);\n };\n }, [ai, layerId, chatId]);\n\n // Executes every render (if the props have changed)\n const randomKey = useRandom();\n const knowledgeKey = props.id ?? randomKey;\n useEffect(() => {\n if (layerKey !== undefined) {\n ai.updateKnowledge(\n layerKey,\n { description, value },\n knowledgeKey,\n chatId\n );\n }\n }, [ai, layerKey, knowledgeKey, description, value, chatId]);\n\n return null;\n});\n\n/**\n * Make a tool available to your AI chat or a one-off request.\n * A tool is a piece of functionality that the AI can call to perform an action\n * or look up information on the user's behalf.\n *\n * Also, tools are used to render custom UIs for tool invocations, which are\n * embedded inside the AI chat.\n *\n * For example:\n *\n * <RegisterAiTool\n * name=\"list-todos\"\n * tool={defineAiTool()({ ... })}\n * />\n *\n * Or scoped to a specific chat:\n *\n * <RegisterAiTool\n * name=\"list-todos\"\n * tool={defineAiTool()({ ... })}\n * chatId=\"chat-1234\"\n * />\n *\n * By mounting this component, the tool is made available.\n * By unmounting this component, the tool will no longer be available.\n */\nexport const RegisterAiTool = memo(function RegisterAiTool({\n chatId,\n name,\n tool,\n enabled,\n}: RegisterAiToolProps) {\n // Register the provided tools to the chat on mount and unregister them on unmount\n const client = useClient();\n const ai = client[kInternal].ai;\n useEffect(() => {\n // The `enabled` prop, when specified, will take precedence over the\n // `enabled` property of the tool itself. This allows enabling or disabling\n // the tool dynamically.\n const toolWithEnabled = enabled !== undefined ? { ...tool, enabled } : tool;\n return ai.registerTool(name, toolWithEnabled, chatId);\n }, [ai, chatId, name, tool, enabled]);\n\n return null;\n});\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable react-hooks/exhaustive-deps */\n/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\nimport {\n useDebugValue,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\n\n/**\n * inlined Object.is polyfill to avoid requiring consumers ship their own\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n */\nfunction is(x: any, y: any) {\n return (\n (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare\n );\n}\n\n// Same as useSyncExternalStore, but supports selector and isEqual arguments.\nexport function useSyncExternalStoreWithSelector<Snapshot, Selection>(\n subscribe: (callback: () => void) => () => void,\n getSnapshot: () => Snapshot,\n getServerSnapshot: void | null | (() => Snapshot),\n selector: (snapshot: Snapshot) => Selection,\n isEqual?: (a: Selection, b: Selection) => boolean\n): Selection {\n type X =\n | { hasValue: true; value: Selection }\n | { hasValue: false; value: null }\n | null;\n\n // Use this to track the rendered snapshot.\n const instRef = useRef<X>(null);\n\n let inst: X;\n if (instRef.current === null) {\n inst = {\n hasValue: false,\n value: null,\n };\n instRef.current = inst;\n } else {\n inst = instRef.current;\n }\n\n const [getSelection, getServerSelection] = useMemo(() => {\n // Track the memoized state using closure variables that are local to this\n // memoized instance of a getSnapshot function. Intentionally not using a\n // useRef hook, because that state would be shared across all concurrent\n // copies of the hook/component.\n let hasMemo = false;\n let memoizedSnapshot: unknown;\n let memoizedSelection: Selection;\n const memoizedSelector = (nextSnapshot: Snapshot) => {\n if (!hasMemo) {\n // The first time the hook is called, there is no memoized result.\n hasMemo = true;\n memoizedSnapshot = nextSnapshot;\n const nextSelection = selector(nextSnapshot);\n if (isEqual !== undefined) {\n // Even if the selector has changed, the currently rendered selection\n // may be equal to the new selection. We should attempt to reuse the\n // current value if possible, to preserve downstream memoizations.\n if (inst.hasValue) {\n const currentSelection = inst.value;\n if (isEqual(currentSelection, nextSelection)) {\n memoizedSelection = currentSelection!;\n return currentSelection;\n }\n }\n }\n memoizedSelection = nextSelection;\n return nextSelection;\n }\n\n // We may be able to reuse the previous invocation's result.\n const prevSnapshot: Snapshot = memoizedSnapshot as any;\n const prevSelection: Selection = memoizedSelection as any;\n\n if (is(prevSnapshot, nextSnapshot)) {\n // The snapshot is the same as last time. Reuse the previous selection.\n return prevSelection;\n }\n\n // The snapshot has changed, so we need to compute a new selection.\n const nextSelection = selector(nextSnapshot);\n\n // If a custom isEqual function is provided, use that to check if the data\n // has changed. If it hasn't, return the previous selection. That signals\n // to React that the selections are conceptually equal, and we can bail\n // out of rendering.\n if (isEqual !== undefined && isEqual(prevSelection, nextSelection)) {\n // The snapshot still has changed, so make sure to update to not keep\n // old references alive\n memoizedSnapshot = nextSnapshot;\n return prevSelection;\n }\n\n memoizedSnapshot = nextSnapshot;\n memoizedSelection = nextSelection;\n return nextSelection;\n };\n\n const maybeGetServerSnapshot =\n getServerSnapshot === undefined ? null : getServerSnapshot;\n const getSnapshotWithSelector = () => memoizedSelector(getSnapshot());\n const getServerSnapshotWithSelector =\n maybeGetServerSnapshot === null\n ? undefined\n : () => memoizedSelector(maybeGetServerSnapshot());\n return [getSnapshotWithSelector, getServerSnapshotWithSelector];\n }, [getSnapshot, getServerSnapshot, selector, isEqual]);\n\n const value = useSyncExternalStore(\n subscribe,\n getSelection,\n getServerSelection\n );\n\n useEffect(() => {\n inst.hasValue = true;\n inst.value = value;\n }, [value]);\n\n useDebugValue(value);\n return value;\n}\n","import type { ISignal } from \"@liveblocks/core\";\nimport { MutableSignal } from \"@liveblocks/core\";\n\nimport { useSyncExternalStoreWithSelector } from \"./use-sync-external-store-with-selector\";\n\nconst identity = <T>(value: T): T => value;\n\nexport function useSignal<T>(signal: ISignal<T>): T;\nexport function useSignal<T, V>(\n signal: ISignal<T>,\n selector: (value: T) => V,\n isEqual?: (a: V, b: V) => boolean\n): V;\nexport function useSignal<T, V>(\n signal: ISignal<T>,\n selector?: (value: T) => V,\n isEqual?: (a: V, b: V) => boolean\n): T | V {\n if (signal instanceof MutableSignal) {\n throw new Error(\n \"Using a mutable Signal with useSignal will likely not work as expected.\"\n );\n }\n return useSyncExternalStoreWithSelector(\n signal.subscribe,\n signal.get,\n signal.get,\n selector ?? (identity as (value: T) => V),\n isEqual\n );\n}\n","import type {\n BaseMetadata,\n BaseUserMeta,\n Client,\n ClientOptions,\n ThreadData,\n} from \"@liveblocks/client\";\nimport type {\n AiUserMessage,\n AsyncResult,\n BaseGroupInfo,\n BaseRoomInfo,\n CopilotId,\n DCM,\n DTM,\n DU,\n LiveblocksError,\n MessageId,\n OpaqueClient,\n PartialNotificationSettings,\n SyncStatus,\n WithRequired,\n} from \"@liveblocks/core\";\nimport {\n assert,\n console,\n createClient,\n DefaultMap,\n HttpError,\n kInternal,\n makePoller,\n raise,\n shallow,\n} from \"@liveblocks/core\";\nimport type { PropsWithChildren } from \"react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n} from \"react\";\n\nimport { RegisterAiKnowledge, RegisterAiTool } from \"./ai\";\nimport { config } from \"./config\";\nimport {\n ClientContext,\n useClient,\n useClientOrNull,\n useIsInsideRoom,\n} from \"./contexts\";\nimport { ASYNC_OK } from \"./lib/AsyncResult\";\nimport { ensureNotServerSide } from \"./lib/ssr\";\nimport { useInitial, useInitialUnlessFunction } from \"./lib/use-initial\";\nimport { useLatest } from \"./lib/use-latest\";\nimport { use } from \"./lib/use-polyfill\";\nimport type {\n AiChatAsyncResult,\n AiChatAsyncSuccess,\n AiChatMessagesAsyncResult,\n AiChatMessagesAsyncSuccess,\n AiChatsAsyncResult,\n AiChatsAsyncSuccess,\n AiChatStatus,\n CreateAiChatOptions,\n GroupInfoAsyncResult,\n GroupInfoAsyncSuccess,\n InboxNotificationsAsyncResult,\n LiveblocksContextBundle,\n NotificationSettingsAsyncResult,\n NotificationSettingsAsyncSuccess,\n RoomInfoAsyncResult,\n RoomInfoAsyncSuccess,\n SendAiMessageOptions,\n SharedContextBundle,\n ThreadsAsyncResult,\n ThreadsAsyncSuccess,\n UnreadInboxNotificationsCountAsyncResult,\n UrlMetadataAsyncResult,\n UrlMetadataAsyncSuccess,\n UseAiChatsOptions,\n UseInboxNotificationsOptions,\n UserAsyncResult,\n UserAsyncSuccess,\n UseSendAiMessageOptions,\n UseSyncStatusOptions,\n UseUserThreadsOptions,\n} from \"./types\";\nimport {\n makeAiChatsQueryKey,\n makeInboxNotificationsQueryKey,\n makeUserThreadsQueryKey,\n UmbrellaStore,\n} from \"./umbrella-store\";\nimport { useSignal } from \"./use-signal\";\nimport { useSyncExternalStoreWithSelector } from \"./use-sync-external-store-with-selector\";\n\nfunction missingUserError(userId: string) {\n return new Error(`resolveUsers didn't return anything for user '${userId}'`);\n}\n\nfunction missingRoomInfoError(roomId: string) {\n return new Error(\n `resolveRoomsInfo didn't return anything for room '${roomId}'`\n );\n}\n\nfunction missingGroupInfoError(groupId: string) {\n return new Error(\n `resolveGroupsInfo didn't return anything for group '${groupId}'`\n );\n}\n\nfunction identity<T>(x: T): T {\n return x;\n}\n\nconst _umbrellaStores = new WeakMap<\n OpaqueClient,\n UmbrellaStore<BaseMetadata, BaseMetadata>\n>();\nconst _extras = new WeakMap<\n OpaqueClient,\n ReturnType<typeof makeLiveblocksExtrasForClient>\n>();\nconst _bundles = new WeakMap<\n OpaqueClient,\n LiveblocksContextBundle<BaseUserMeta, BaseMetadata, BaseMetadata>\n>();\n\nfunction selectorFor_useUnreadInboxNotificationsCount(\n result: UnreadInboxNotificationsCountAsyncResult\n): UnreadInboxNotificationsCountAsyncResult {\n if (!(\"count\" in result) || result.count === undefined) {\n // Can be loading or error states\n return result;\n }\n\n return ASYNC_OK(\"count\", result.count);\n}\n\nfunction selectorFor_useUser<U extends BaseUserMeta>(\n state: AsyncResult<U[\"info\"] | undefined> | undefined,\n userId: string\n): UserAsyncResult<U[\"info\"]> {\n if (state === undefined || state?.isLoading) {\n return state ?? { isLoading: true };\n }\n\n if (state.error) {\n return state;\n }\n\n // If this is a \"success\" state, but there still is no data, then it means\n // the \"resolving of this user\" returned undefined. In that case, still treat\n // this as an error state.\n if (!state.data) {\n return {\n isLoading: false,\n error: missingUserError(userId),\n };\n }\n\n return {\n isLoading: false,\n user: state.data,\n };\n}\n\nfunction selectorFor_useRoomInfo(\n state: AsyncResult<BaseRoomInfo | undefined> | undefined,\n roomId: string\n): RoomInfoAsyncResult {\n if (state === undefined || state?.isLoading) {\n return state ?? { isLoading: true };\n }\n\n if (state.error) {\n return state;\n }\n\n // If this is a \"success\" state, but there still is no data, then it means\n // the \"resolving of this room info\" returned undefined. In that case, still treat\n // this as an error state.\n if (!state.data) {\n return {\n isLoading: false,\n error: missingRoomInfoError(roomId),\n };\n }\n\n return {\n isLoading: false,\n info: state.data,\n };\n}\n\nfunction selectorFor_useGroupInfo(\n state: AsyncResult<BaseGroupInfo | undefined> | undefined,\n groupId: string\n): GroupInfoAsyncResult {\n if (state === undefined || state?.isLoading) {\n return state ?? { isLoading: true };\n }\n\n if (state.error) {\n return state;\n }\n\n // If this is a \"success\" state, but there still is no data, then it means\n // the \"resolving of this group info\" returned undefined. In that case, still treat\n // this as an error state.\n if (!state.data) {\n return {\n isLoading: false,\n error: missingGroupInfoError(groupId),\n };\n }\n\n return {\n isLoading: false,\n info: state.data,\n };\n}\n\nfunction getOrCreateContextBundle<\n U extends BaseUserMeta,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: OpaqueClient): LiveblocksContextBundle<U, TM, CM> {\n let bundle = _bundles.get(client);\n if (!bundle) {\n bundle = makeLiveblocksContextBundle(client);\n _bundles.set(client, bundle);\n }\n return bundle as unknown as LiveblocksContextBundle<U, TM, CM>;\n}\n\n/**\n * Gets or creates a unique Umbrella store for each unique client instance.\n *\n * @private\n */\nexport function getUmbrellaStoreForClient<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: OpaqueClient): UmbrellaStore<TM, CM> {\n let store = _umbrellaStores.get(client);\n if (!store) {\n store = new UmbrellaStore(client);\n _umbrellaStores.set(client, store);\n }\n return store as unknown as UmbrellaStore<TM, CM>;\n}\n\n// TODO: Likely a better / more clear name for this helper will arise. I'll\n// rename this later. All of these are implementation details to support inbox\n// notifications on a per-client basis.\n/** @internal Only exported for unit tests. */\nexport function getLiveblocksExtrasForClient<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: OpaqueClient) {\n let extras = _extras.get(client);\n if (!extras) {\n extras = makeLiveblocksExtrasForClient(client);\n _extras.set(client, extras);\n }\n\n return extras as unknown as Omit<typeof extras, \"store\"> & {\n store: UmbrellaStore<TM, CM>;\n };\n}\n\n// Connect to the AI socket whenever this hook is called, to use in all AI-related hooks.\n//\n// The internal `ManagedSocket` no-ops when calling `connect()` if it is already connected,\n// so we don't need any conditional logic here. And we don't call `disconnect()` in cleanup\n// here because we don't want to disconnect whenever a single hook unmounts, instead we\n// disconnect when `LiveblocksProvider` unmounts.\n//\n// This is a short-term solution to avoid always asking for an auth token on mount\n// even when AI isn't used.\n//\n// - We maybe could disconnect whenever the last AI-related hook unmounts\n// - We maybe could avoid connecting if we already have a token (from another Liveblocks feature),\n// and already know that the user doesn't have AI enabled\nfunction useEnsureAiConnection(client: OpaqueClient) {\n useEffect(() => {\n client[kInternal].ai.connectInitially();\n }, [client]);\n}\n\nfunction makeLiveblocksExtrasForClient(client: OpaqueClient) {\n const store = getUmbrellaStoreForClient(client);\n // TODO ^ Bind to M type param here\n\n //\n // How pagination and delta updates work\n // =====================================\n //\n // Suppose we call fetchInboxNotifications() for the first time. Then,\n // eventually we'll see this timeline of notifications:\n //\n // <-- Newer Older -->\n // |---o---------o----------o---|\n //\n // o = an inbox notification\n //\n // In this array, there are three entries, ordered from latest to oldest.\n //\n // Now if we call fetchInboxNotifications() again (which is what the\n // periodic poller does), then the array may get updated with newer inbox\n // notifications, meaning entries will appear at the head end of the array.\n // This is a so called \"delta update\".\n //\n // <-- Newer Older -->\n // |--o---o-|---o---------o----------o---|\n // delta\n //\n // Here, two new entries have appeared at the start.\n //\n // Another way to update this array is to use \"pagination\". Pagination will\n // update this list at the _tail_ end.\n //\n // After calling fetchMore():\n //\n // <-- Newer Older -->\n // |--o---o-|---o---------o----------o---|--o--o-o-o-o-o--|\n // page 2\n //\n // And calling fetchMore() another time:\n //\n // <-- Newer Older -->\n // |--o---o-|---o---------o----------o---|--o--o-o-o-o-o--|--o-o---o---o--|\n // page 2 page 3\n //\n // In terms of HTTP requests:\n // - A delta update will perform a GET /v2/c/inbox-notifications?since=...\n // - Pagination will perform a GET /v2/c/inbox-notifications?cursor=...\n //\n\n const notificationsPoller = makePoller(\n async (signal) => {\n try {\n return await store.fetchNotificationsDeltaUpdate(signal);\n } catch (err) {\n console.warn(`Polling new inbox notifications failed: ${String(err)}`);\n throw err;\n }\n },\n config.NOTIFICATIONS_POLL_INTERVAL,\n { maxStaleTimeMs: config.NOTIFICATIONS_MAX_STALE_TIME }\n );\n\n const unreadNotificationsCountPollersByQueryKey = new DefaultMap(\n (queryKey: string) =>\n makePoller(\n async (signal) => {\n try {\n return await store.fetchUnreadNotificationsCount(queryKey, signal);\n } catch (err) {\n console.warn(\n `Polling unread inbox notifications countfailed: ${String(err)}`\n );\n throw err;\n }\n },\n config.NOTIFICATIONS_POLL_INTERVAL,\n { maxStaleTimeMs: config.NOTIFICATIONS_MAX_STALE_TIME }\n )\n );\n\n const userThreadsPoller = makePoller(\n async (signal) => {\n try {\n return await store.fetchUserThreadsDeltaUpdate(signal);\n } catch (err) {\n console.warn(`Polling new user threads failed: ${String(err)}`);\n throw err;\n }\n },\n config.USER_THREADS_POLL_INTERVAL,\n { maxStaleTimeMs: config.USER_THREADS_MAX_STALE_TIME }\n );\n\n const notificationSettingsPoller = makePoller(\n async (signal) => {\n try {\n return await store.refreshNotificationSettings(signal);\n } catch (err) {\n console.warn(\n `Polling new notification settings failed: ${String(err)}`\n );\n throw err;\n }\n },\n config.USER_NOTIFICATION_SETTINGS_INTERVAL,\n { maxStaleTimeMs: config.USER_NOTIFICATION_SETTINGS_MAX_STALE_TIME }\n );\n\n return {\n store,\n notificationsPoller,\n userThreadsPoller,\n notificationSettingsPoller,\n unreadNotificationsCountPollersByQueryKey,\n };\n}\n\nfunction makeLiveblocksContextBundle<\n U extends BaseUserMeta,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: Client<U>): LiveblocksContextBundle<U, TM, CM> {\n // Bind all hooks to the current client instance\n const useInboxNotificationThread = (inboxNotificationId: string) =>\n useInboxNotificationThread_withClient<TM, CM>(client, inboxNotificationId);\n\n const useMarkInboxNotificationAsRead = () =>\n useMarkInboxNotificationAsRead_withClient(client);\n\n const useMarkAllInboxNotificationsAsRead = () =>\n useMarkAllInboxNotificationsAsRead_withClient(client);\n\n const useDeleteInboxNotification = () =>\n useDeleteInboxNotification_withClient(client);\n\n const useDeleteAllInboxNotifications = () =>\n useDeleteAllInboxNotifications_withClient(client);\n\n const useUpdateNotificationSettings = () =>\n useUpdateNotificationSettings_withClient(client);\n\n // NOTE: This version of the LiveblocksProvider does _not_ take any props.\n // This is because we already have a client bound to it.\n function LiveblocksProvider(props: PropsWithChildren) {\n useEnsureNoLiveblocksProvider();\n return (\n <ClientContext.Provider value={client}>\n {props.children}\n </ClientContext.Provider>\n );\n }\n\n const shared = createSharedContext<U>(client);\n\n const bundle: LiveblocksContextBundle<U, TM, CM> = {\n LiveblocksProvider,\n\n useInboxNotifications: (options?: UseInboxNotificationsOptions) =>\n useInboxNotifications_withClient(client, identity, shallow, options),\n useUnreadInboxNotificationsCount: (\n options?: UseInboxNotificationsOptions\n ) => useUnreadInboxNotificationsCount_withClient(client, options),\n\n useMarkInboxNotificationAsRead,\n useMarkAllInboxNotificationsAsRead,\n\n useDeleteInboxNotification,\n useDeleteAllInboxNotifications,\n\n useNotificationSettings: () => useNotificationSettings_withClient(client),\n useUpdateNotificationSettings,\n\n useInboxNotificationThread,\n useUserThreads_experimental,\n\n useAiChats,\n useAiChat,\n useAiChatMessages,\n useAiChatStatus,\n useCreateAiChat,\n useDeleteAiChat,\n useSendAiMessage,\n\n useUrlMetadata,\n\n ...shared.classic,\n\n suspense: {\n LiveblocksProvider,\n\n useInboxNotifications: (options?: UseInboxNotificationsOptions) =>\n useInboxNotificationsSuspense_withClient(client, options),\n useUnreadInboxNotificationsCount: (\n options?: UseInboxNotificationsOptions\n ) => useUnreadInboxNotificationsCountSuspense_withClient(client, options),\n\n useMarkInboxNotificationAsRead,\n useMarkAllInboxNotificationsAsRead,\n\n useDeleteInboxNotification,\n useDeleteAllInboxNotifications,\n\n useInboxNotificationThread,\n\n useNotificationSettings: () =>\n useNotificationSettingsSuspense_withClient(client),\n useUpdateNotificationSettings,\n\n useUserThreads_experimental: useUserThreadsSuspense_experimental,\n\n useAiChats: useAiChatsSuspense,\n useAiChat: useAiChatSuspense,\n useAiChatMessages: useAiChatMessagesSuspense,\n useAiChatStatus,\n useCreateAiChat,\n useDeleteAiChat,\n useSendAiMessage,\n\n useUrlMetadata: useUrlMetadataSuspense,\n\n ...shared.suspense,\n },\n };\n return bundle;\n}\n\nfunction useInboxNotifications_withClient<T>(\n client: OpaqueClient,\n selector: (result: InboxNotificationsAsyncResult) => T,\n isEqual: (a: T, b: T) => boolean,\n options?: UseInboxNotificationsOptions\n): T {\n const { store, notificationsPoller: poller } =\n getLiveblocksExtrasForClient(client);\n\n const queryKey = makeInboxNotificationsQueryKey(options?.query);\n\n // Trigger initial loading of inbox notifications if it hasn't started\n // already, but don't await its promise.\n useEffect(\n () =>\n void store.outputs.loadingNotifications\n .getOrCreate(queryKey)\n .waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => {\n poller.dec();\n };\n }, [poller]);\n\n return useSignal(\n store.outputs.loadingNotifications.getOrCreate(queryKey).signal,\n selector,\n isEqual\n );\n}\n\nfunction useInboxNotificationsSuspense_withClient(\n client: OpaqueClient,\n options?: UseInboxNotificationsOptions\n) {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const store = getLiveblocksExtrasForClient(client).store;\n\n const queryKey = makeInboxNotificationsQueryKey(options?.query);\n\n // Suspend until there are at least some inbox notifications\n use(\n store.outputs.loadingNotifications.getOrCreate(queryKey).waitUntilLoaded()\n );\n\n // We're in a Suspense world here, and as such, the useInboxNotifications()\n // hook is expected to only return success results when we're here.\n const result = useInboxNotifications_withClient(\n client,\n identity,\n shallow,\n options\n );\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\nfunction useUnreadInboxNotificationsCount_withClient(\n client: OpaqueClient,\n options?: UseInboxNotificationsOptions\n) {\n const { store, unreadNotificationsCountPollersByQueryKey: pollers } =\n getLiveblocksExtrasForClient(client);\n\n const queryKey = makeInboxNotificationsQueryKey(options?.query);\n\n const poller = pollers.getOrCreate(queryKey);\n\n useEffect(\n () =>\n void store.outputs.unreadNotificationsCount\n .getOrCreate(queryKey)\n .waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => {\n poller.dec();\n };\n }, [poller]);\n\n return useSignal(\n store.outputs.unreadNotificationsCount.getOrCreate(queryKey).signal,\n selectorFor_useUnreadInboxNotificationsCount,\n shallow\n );\n}\n\nfunction useUnreadInboxNotificationsCountSuspense_withClient(\n client: OpaqueClient,\n options?: UseInboxNotificationsOptions\n) {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const store = getLiveblocksExtrasForClient(client).store;\n\n const queryKey = makeInboxNotificationsQueryKey(options?.query);\n\n // Suspend until there are at least some unread inbox notifications count\n use(\n store.outputs.unreadNotificationsCount\n .getOrCreate(queryKey)\n .waitUntilLoaded()\n );\n\n const result = useUnreadInboxNotificationsCount_withClient(client, options);\n assert(!result.isLoading, \"Did not expect loading\");\n assert(!result.error, \"Did not expect error\");\n return result;\n}\n\nfunction useMarkInboxNotificationAsRead_withClient(client: OpaqueClient) {\n return useCallback(\n (inboxNotificationId: string) => {\n const { store, unreadNotificationsCountPollersByQueryKey } =\n getLiveblocksExtrasForClient(client);\n\n const readAt = new Date();\n const optimisticId = store.optimisticUpdates.add({\n type: \"mark-inbox-notification-as-read\",\n inboxNotificationId,\n readAt,\n });\n\n client.markInboxNotificationAsRead(inboxNotificationId).then(\n () => {\n // Replace the optimistic update by the real thing\n store.markInboxNotificationRead(\n inboxNotificationId,\n readAt,\n optimisticId\n );\n\n // Force a re-fetch of the unread notifications count\n for (const poller of unreadNotificationsCountPollersByQueryKey.values()) {\n poller.markAsStale();\n poller.pollNowIfStale();\n }\n },\n (err: Error) => {\n store.optimisticUpdates.remove(optimisticId);\n // XXX_vincent Add unit test for this error\n client[kInternal].emitError(\n {\n type: \"MARK_INBOX_NOTIFICATION_AS_READ_ERROR\",\n inboxNotificationId,\n },\n err\n );\n }\n );\n },\n [client]\n );\n}\n\nfunction useMarkAllInboxNotificationsAsRead_withClient(client: OpaqueClient) {\n return useCallback(() => {\n const { store, unreadNotificationsCountPollersByQueryKey } =\n getLiveblocksExtrasForClient(client);\n const readAt = new Date();\n const optimisticId = store.optimisticUpdates.add({\n type: \"mark-all-inbox-notifications-as-read\",\n readAt,\n });\n\n client.markAllInboxNotificationsAsRead().then(\n () => {\n // Replace the optimistic update by the real thing\n store.markAllInboxNotificationsRead(optimisticId, readAt);\n\n // Force a re-fetch of the unread notifications count\n for (const poller of unreadNotificationsCountPollersByQueryKey.values()) {\n poller.markAsStale();\n poller.pollNowIfStale();\n }\n },\n (err: Error) => {\n store.optimisticUpdates.remove(optimisticId);\n client[kInternal].emitError(\n // No roomId, threadId, commentId to include for this error\n { type: \"MARK_ALL_INBOX_NOTIFICATIONS_AS_READ_ERROR\" },\n err\n );\n }\n );\n }, [client]);\n}\n\nfunction useDeleteInboxNotification_withClient(client: OpaqueClient) {\n return useCallback(\n (inboxNotificationId: string) => {\n const { store, unreadNotificationsCountPollersByQueryKey } =\n getLiveblocksExtrasForClient(client);\n\n const deletedAt = new Date();\n const optimisticId = store.optimisticUpdates.add({\n type: \"delete-inbox-notification\",\n inboxNotificationId,\n deletedAt,\n });\n\n client.deleteInboxNotification(inboxNotificationId).then(\n () => {\n // Replace the optimistic update by the real thing\n store.deleteInboxNotification(inboxNotificationId, optimisticId);\n\n // Force a re-fetch of the unread notifications count\n for (const poller of unreadNotificationsCountPollersByQueryKey.values()) {\n poller.markAsStale();\n poller.pollNowIfStale();\n }\n },\n (err: Error) => {\n store.optimisticUpdates.remove(optimisticId);\n // XXX_vincent Add unit test for this error\n client[kInternal].emitError(\n { type: \"DELETE_INBOX_NOTIFICATION_ERROR\", inboxNotificationId },\n err\n );\n }\n );\n },\n [client]\n );\n}\n\nfunction useDeleteAllInboxNotifications_withClient(client: OpaqueClient) {\n return useCallback(() => {\n const { store, unreadNotificationsCountPollersByQueryKey } =\n getLiveblocksExtrasForClient(client);\n const deletedAt = new Date();\n const optimisticId = store.optimisticUpdates.add({\n type: \"delete-all-inbox-notifications\",\n deletedAt,\n });\n\n client.deleteAllInboxNotifications().then(\n () => {\n // Replace the optimistic update by the real thing\n store.deleteAllInboxNotifications(optimisticId);\n\n // Force a re-fetch of the unread notifications count\n for (const poller of unreadNotificationsCountPollersByQueryKey.values()) {\n poller.markAsStale();\n poller.pollNowIfStale();\n }\n },\n (err: Error) => {\n store.optimisticUpdates.remove(optimisticId);\n // XXX_vincent Add unit test for this error\n client[kInternal].emitError(\n { type: \"DELETE_ALL_INBOX_NOTIFICATIONS_ERROR\" },\n err\n );\n }\n );\n }, [client]);\n}\n\nfunction useInboxNotificationThread_withClient<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: OpaqueClient, inboxNotificationId: string): ThreadData<TM, CM> {\n const { store } = getLiveblocksExtrasForClient<TM, CM>(client);\n return useSignal(\n store.outputs.threadifications,\n useCallback(\n (state) => {\n const inboxNotification =\n state.notificationsById[inboxNotificationId] ??\n raise(\n `Inbox notification with ID \"${inboxNotificationId}\" not found`\n );\n\n if (inboxNotification.kind !== \"thread\") {\n raise(\n `Inbox notification with ID \"${inboxNotificationId}\" is not of kind \"thread\"`\n );\n }\n\n const thread =\n state.threadsDB.get(inboxNotification.threadId) ??\n raise(\n `Thread with ID \"${inboxNotification.threadId}\" not found, this inbox notification might not be of kind \"thread\"`\n );\n\n return thread;\n },\n [inboxNotificationId]\n )\n );\n}\n\nfunction useUpdateNotificationSettings_withClient(\n client: OpaqueClient\n): (settings: PartialNotificationSettings) => void {\n return useCallback(\n (settings: PartialNotificationSettings): void => {\n const { store } = getLiveblocksExtrasForClient(client);\n const optimisticUpdateId = store.optimisticUpdates.add({\n type: \"update-notification-settings\",\n settings,\n });\n\n client.updateNotificationSettings(settings).then(\n (settings) => {\n // Replace the optimistic update by the real thing\n store.updateNotificationSettings_confirmOptimisticUpdate(\n settings,\n optimisticUpdateId\n );\n },\n (err: Error) => {\n // Remove optimistic update when it fails\n store.optimisticUpdates.remove(optimisticUpdateId);\n // Check if the error is an HTTP error\n if (err instanceof HttpError) {\n if (err.status === 422) {\n const msg = [err.details?.error, err.details?.reason]\n .filter(Boolean)\n .join(\"\\n\");\n console.error(msg);\n }\n\n client[kInternal].emitError(\n {\n type: \"UPDATE_NOTIFICATION_SETTINGS_ERROR\",\n },\n err\n );\n }\n // A non-HTTP error is unexpected and must be considered as a bug.\n // We should fix it and do not notify users about it.\n else {\n throw err;\n }\n }\n );\n },\n [client]\n );\n}\n\nfunction useNotificationSettings_withClient(\n client: OpaqueClient\n): [\n NotificationSettingsAsyncResult,\n (settings: PartialNotificationSettings) => void,\n] {\n const updateNotificationSettings =\n useUpdateNotificationSettings_withClient(client);\n\n const { store, notificationSettingsPoller: poller } =\n getLiveblocksExtrasForClient(client);\n\n useEffect(() => {\n void store.outputs.notificationSettings.waitUntilLoaded();\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n });\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => {\n poller.dec();\n };\n }, [poller]);\n\n const result = useSignal(store.outputs.notificationSettings.signal);\n\n return useMemo(() => {\n return [result, updateNotificationSettings];\n }, [result, updateNotificationSettings]);\n}\n\nfunction useNotificationSettingsSuspense_withClient(\n client: OpaqueClient\n): [\n NotificationSettingsAsyncSuccess,\n (settings: PartialNotificationSettings) => void,\n] {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const store = getLiveblocksExtrasForClient(client).store;\n\n // Suspend until there are at least some notification settings\n use(store.outputs.notificationSettings.waitUntilLoaded());\n\n // We're in a Suspense world here, and as such, the useNotificationSettings()\n // hook is expected to only return success results when we're here.\n const [result, updateNotificationSettings] =\n useNotificationSettings_withClient(client);\n\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n\n return useMemo(() => {\n return [result, updateNotificationSettings];\n }, [result, updateNotificationSettings]);\n}\n\nfunction useUser_withClient<U extends BaseUserMeta>(\n client: Client<U>,\n userId: string\n): UserAsyncResult<U[\"info\"]> {\n const usersStore = client[kInternal].usersStore;\n\n const getUserState = useCallback(\n () => usersStore.getItemState(userId),\n [usersStore, userId]\n );\n\n const selector = useCallback(\n (state: ReturnType<typeof getUserState>) =>\n selectorFor_useUser(state, userId),\n [userId]\n );\n\n const result = useSyncExternalStoreWithSelector(\n usersStore.subscribe,\n getUserState,\n getUserState,\n selector,\n shallow\n );\n\n // Trigger a fetch if we don't have any data yet (whether initially or after an invalidation)\n useEffect(\n () => void usersStore.enqueue(userId)\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call usersStore.enqueue on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger evaluation\n // of the userId.\n // 2. All other subsequent renders now are a no-op (from the implementation\n // of .enqueue)\n // 3. If ever the userId gets invalidated, the user would be fetched again.\n );\n\n return result;\n}\n\nfunction useUserSuspense_withClient<U extends BaseUserMeta>(\n client: Client<U>,\n userId: string\n) {\n const usersStore = client[kInternal].usersStore;\n\n const getUserState = useCallback(\n () => usersStore.getItemState(userId),\n [usersStore, userId]\n );\n const userState = getUserState();\n\n if (!userState || userState.isLoading) {\n throw usersStore.enqueue(userId);\n }\n\n if (userState.error) {\n throw userState.error;\n }\n\n // Throw an error if `undefined` was returned by `resolveUsers` for this user ID\n if (!userState.data) {\n throw missingUserError(userId);\n }\n\n const state = useSyncExternalStore(\n usersStore.subscribe,\n getUserState,\n getUserState\n );\n assert(state !== undefined, \"Unexpected missing state\");\n assert(!state.isLoading, \"Unexpected loading state\");\n assert(!state.error, \"Unexpected error state\");\n return {\n isLoading: false,\n user: state.data,\n error: undefined,\n } as const;\n}\n\nfunction useRoomInfo_withClient(\n client: OpaqueClient,\n roomId: string\n): RoomInfoAsyncResult {\n const roomsInfoStore = client[kInternal].roomsInfoStore;\n\n const getRoomInfoState = useCallback(\n () => roomsInfoStore.getItemState(roomId),\n [roomsInfoStore, roomId]\n );\n\n const selector = useCallback(\n (state: ReturnType<typeof getRoomInfoState>) =>\n selectorFor_useRoomInfo(state, roomId),\n [roomId]\n );\n\n const result = useSyncExternalStoreWithSelector(\n roomsInfoStore.subscribe,\n getRoomInfoState,\n getRoomInfoState,\n selector,\n shallow\n );\n\n // Trigger a fetch if we don't have any data yet (whether initially or after an invalidation)\n useEffect(\n () => void roomsInfoStore.enqueue(roomId)\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call roomsInfoStore.enqueue on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger evaluation\n // of the roomId.\n // 2. All other subsequent renders now are a no-op (from the implementation\n // of .enqueue)\n // 3. If ever the roomId gets invalidated, the room info would be fetched again.\n );\n\n return result;\n}\n\nfunction useRoomInfoSuspense_withClient(client: OpaqueClient, roomId: string) {\n const roomsInfoStore = client[kInternal].roomsInfoStore;\n\n const getRoomInfoState = useCallback(\n () => roomsInfoStore.getItemState(roomId),\n [roomsInfoStore, roomId]\n );\n const roomInfoState = getRoomInfoState();\n\n if (!roomInfoState || roomInfoState.isLoading) {\n throw roomsInfoStore.enqueue(roomId);\n }\n\n if (roomInfoState.error) {\n throw roomInfoState.error;\n }\n\n // Throw an error if `undefined` was returned by `resolveRoomsInfo` for this room ID\n if (!roomInfoState.data) {\n throw missingRoomInfoError(roomId);\n }\n\n const state = useSyncExternalStore(\n roomsInfoStore.subscribe,\n getRoomInfoState,\n getRoomInfoState\n );\n assert(state !== undefined, \"Unexpected missing state\");\n assert(!state.isLoading, \"Unexpected loading state\");\n assert(!state.error, \"Unexpected error state\");\n assert(state.data !== undefined, \"Unexpected missing room info data\");\n return {\n isLoading: false,\n info: state.data,\n error: undefined,\n } as const;\n}\n\nfunction useGroupInfo_withClient(\n client: OpaqueClient,\n groupId: string\n): GroupInfoAsyncResult {\n const groupsInfoStore = client[kInternal].groupsInfoStore;\n\n const getGroupInfoState = useCallback(\n () => groupsInfoStore.getItemState(groupId),\n [groupsInfoStore, groupId]\n );\n\n const selector = useCallback(\n (state: ReturnType<typeof getGroupInfoState>) =>\n selectorFor_useGroupInfo(state, groupId),\n [groupId]\n );\n\n const result = useSyncExternalStoreWithSelector(\n groupsInfoStore.subscribe,\n getGroupInfoState,\n getGroupInfoState,\n selector,\n shallow\n );\n\n // Trigger a fetch if we don't have any data yet (whether initially or after an invalidation)\n useEffect(\n () => void groupsInfoStore.enqueue(groupId)\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call groupsInfoStore.enqueue on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger evaluation\n // of the groupId.\n // 2. All other subsequent renders now are a no-op (from the implementation\n // of .enqueue)\n // 3. If ever the groupId gets invalidated, the group info would be fetched again.\n );\n\n return result;\n}\n\nfunction useGroupInfoSuspense_withClient(\n client: OpaqueClient,\n groupId: string\n) {\n const groupsInfoStore = client[kInternal].groupsInfoStore;\n\n const getGroupInfoState = useCallback(\n () => groupsInfoStore.getItemState(groupId),\n [groupsInfoStore, groupId]\n );\n const groupInfoState = getGroupInfoState();\n\n if (!groupInfoState || groupInfoState.isLoading) {\n throw groupsInfoStore.enqueue(groupId);\n }\n\n if (groupInfoState.error) {\n throw groupInfoState.error;\n }\n\n // Throw an error if `undefined` was returned by `resolveGroupsInfo` for this group ID\n if (!groupInfoState.data) {\n throw missingGroupInfoError(groupId);\n }\n\n const state = useSyncExternalStore(\n groupsInfoStore.subscribe,\n getGroupInfoState,\n getGroupInfoState\n );\n assert(state !== undefined, \"Unexpected missing state\");\n assert(!state.isLoading, \"Unexpected loading state\");\n assert(!state.error, \"Unexpected error state\");\n assert(state.data !== undefined, \"Unexpected missing group info data\");\n return {\n isLoading: false,\n info: state.data,\n error: undefined,\n } as const;\n}\n\n/**\n * (Private beta) Returns the chats for the current user.\n *\n * @example\n * const { chats } = useAiChats();\n */\nfunction useAiChats(options?: UseAiChatsOptions): AiChatsAsyncResult {\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n const queryKey = makeAiChatsQueryKey(options?.query);\n\n useEnsureAiConnection(client);\n\n useEffect(\n () => void store.outputs.aiChats.getOrCreate(queryKey).waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n return useSignal(\n store.outputs.aiChats.getOrCreate(queryKey).signal,\n identity,\n shallow\n );\n}\n\nfunction useAiChatsSuspense(options?: UseAiChatsOptions): AiChatsAsyncSuccess {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEnsureAiConnection(client);\n\n const queryKey = makeAiChatsQueryKey(options?.query);\n\n use(store.outputs.aiChats.getOrCreate(queryKey).waitUntilLoaded());\n\n const result = useAiChats(options);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\nfunction useAiChatMessages(\n chatId: string,\n /** @internal */\n options?: { branchId?: MessageId }\n): AiChatMessagesAsyncResult {\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEnsureAiConnection(client);\n\n useEffect(\n () =>\n void store.outputs.messagesByChatId\n .getOrCreate(chatId)\n .getOrCreate(options?.branchId ?? null)\n .waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n return useSignal(\n store.outputs.messagesByChatId\n .getOrCreate(chatId)\n .getOrCreate(options?.branchId ?? null).signal\n );\n}\n\nfunction useAiChatMessagesSuspense(\n chatId: string,\n /** @internal */\n options?: { branchId?: MessageId }\n): AiChatMessagesAsyncSuccess {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEnsureAiConnection(client);\n\n use(\n store.outputs.messagesByChatId\n .getOrCreate(chatId)\n .getOrCreate(options?.branchId ?? null)\n .waitUntilLoaded()\n );\n\n const result = useAiChatMessages(chatId, options);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\nfunction useAiChat(chatId: string): AiChatAsyncResult {\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEnsureAiConnection(client);\n\n useEffect(\n () => void store.outputs.aiChatById.getOrCreate(chatId).waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n return useSignal(store.outputs.aiChatById.getOrCreate(chatId).signal);\n}\n\nfunction useAiChatSuspense(chatId: string): AiChatAsyncSuccess {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEnsureAiConnection(client);\n\n use(store.outputs.aiChatById.getOrCreate(chatId).waitUntilLoaded());\n\n const result = useAiChat(chatId);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\n/**\n * Returns metadata for a given URL.\n *\n * @example\n * const { metadata, error, isLoading } = useUrlMetadata(\"https://liveblocks.io\");\n */\nfunction useUrlMetadata(url: string): UrlMetadataAsyncResult {\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEffect(\n () => void store.outputs.urlMetadataByUrl.getOrCreate(url).waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n return useSignal(store.outputs.urlMetadataByUrl.getOrCreate(url).signal);\n}\n\n/**\n * Returns metadata for a given URL.\n *\n * @example\n * const { metadata } = useUrlMetadata(\"https://liveblocks.io\");\n */\nfunction useUrlMetadataSuspense(url: string): UrlMetadataAsyncSuccess {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n use(store.outputs.urlMetadataByUrl.getOrCreate(url).waitUntilLoaded());\n\n const result = useUrlMetadata(url);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\n/**\n * Returns a function that creates an AI chat.\n *\n * If you do not pass a title for the chat, it will be automatically computed\n * after the first AI response.\n *\n * @example\n * const createAiChat = useCreateAiChat();\n *\n * // Create a chat with an automatically generated title\n * createAiChat(\"ai-chat-id\");\n *\n * // Create a chat with a custom title\n * createAiChat({ id: \"ai-chat-id\", title: \"My AI chat\" });\n */\nfunction useCreateAiChat(): {\n (chatId: string): void;\n (options: CreateAiChatOptions): void;\n} {\n const client = useClient();\n\n return useCallback(\n (options: string | CreateAiChatOptions) => {\n if (typeof options === \"string\") {\n options = { id: options };\n }\n\n client[kInternal].ai\n .getOrCreateChat(options.id, {\n title: options.title,\n metadata: options.metadata,\n })\n .catch((err) => {\n console.error(\n `Failed to create chat with ID \"${options.id}\": ${String(err)}`\n );\n });\n },\n [client]\n );\n}\n\n/**\n * Returns a function that deletes the AI chat with the specified id.\n *\n * @example\n * const deleteAiChat = useDeleteAiChat();\n * deleteAiChat(\"ai-chat-id\");\n */\nfunction useDeleteAiChat() {\n const client = useClient();\n\n return useCallback(\n (chatId: string) => {\n client[kInternal].ai.deleteChat(chatId).catch((err) => {\n console.error(\n `Failed to delete chat with ID \"${chatId}\": ${String(err)}`\n );\n });\n },\n [client]\n );\n}\n\nconst DISCONNECTED = Object.freeze({ status: \"disconnected\" });\nconst LOADING = Object.freeze({ status: \"loading\" });\nconst IDLE = Object.freeze({ status: \"idle\" });\n\n/**\n * Returns the status of an AI chat, indicating whether it's disconnected, loading, idle\n * or actively generating content. This is a convenience hook that derives its state from\n * the latest assistant message in the chat.\n *\n * Re-renders whenever any of the relevant fields change.\n *\n * @param chatId - The ID of the chat to monitor\n * @returns The current status of the AI chat\n *\n * @example\n * ```tsx\n * import { useAiChatStatus } from \"@liveblocks/react\";\n *\n * function ChatStatus() {\n * const { status, partType, toolName } = useAiChatStatus(\"my-chat\");\n * console.log(status); // \"disconnected\" | \"loading\" | \"idle\" | \"generating\"\n * console.log(status.partType); // \"text\" | \"tool-invocation\" | ...\n * console.log(status.toolName); // string | undefined\n * }\n * ```\n */\nfunction useAiChatStatus(\n chatId: string,\n /** @internal */\n branchId?: MessageId\n): AiChatStatus {\n const client = useClient();\n const store = getUmbrellaStoreForClient(client);\n\n useEnsureAiConnection(client);\n\n useEffect(\n () =>\n void store.outputs.messagesByChatId\n .getOrCreate(chatId)\n .getOrCreate(branchId ?? null)\n .waitUntilLoaded()\n );\n\n const isAvailable = useSignal(\n // Subscribe to connection status signal\n client[kInternal].ai.signals.statusΣ,\n // \"Disconnected\" means the AI service is not available\n // as it represents a final error status.\n (status) => status !== \"disconnected\"\n );\n\n const chatStatus = useSignal(\n // Signal\n store.outputs.messagesByChatId\n .getOrCreate(chatId)\n .getOrCreate(branchId ?? null).signal,\n\n // Selector\n (result) => {\n if (result.isLoading) return LOADING satisfies AiChatStatus;\n if (result.error) return IDLE satisfies AiChatStatus;\n\n const messages = result.messages;\n const lastMessage = messages[messages.length - 1];\n\n if (lastMessage?.role !== \"assistant\") return IDLE satisfies AiChatStatus;\n if (\n lastMessage.status !== \"generating\" &&\n lastMessage.status !== \"awaiting-tool\"\n )\n return IDLE satisfies AiChatStatus;\n\n const contentSoFar = lastMessage.contentSoFar;\n const lastPart = contentSoFar[contentSoFar.length - 1];\n\n if (lastPart?.type === \"tool-invocation\") {\n return {\n status: \"generating\",\n partType: \"tool-invocation\",\n toolName: lastPart.name,\n } satisfies AiChatStatus;\n } else {\n return {\n status: \"generating\",\n partType: lastPart?.type,\n } satisfies AiChatStatus;\n }\n },\n\n // Consider { status: \"generating\", partType: \"text\" } and { status: \"generating\", partType: \"text\" } equal\n shallow\n );\n\n if (!isAvailable) {\n return DISCONNECTED;\n }\n\n return chatStatus;\n}\n\n/**\n * Returns a function to send a message in an AI chat.\n *\n * @example\n * const sendAiMessage = useSendAiMessage(\"chat-id\");\n * sendAiMessage(\"Hello, Liveblocks AI!\");\n *\n * You can set options related to the message being sent, such as the copilot ID to use.\n *\n * @example\n * const sendAiMessage = useSendAiMessage(\"chat-id\", { copilotId: \"co_xxx\" });\n * sendAiMessage(\"Hello, Liveblocks AI!\");\n *\n * @example\n * const sendAiMessage = useSendAiMessage(\"chat-id\", { copilotId: \"co_xxx\" });\n * sendAiMessage({ text: \"Hello, Liveblocks AI!\", copilotId: \"co_yyy\" });\n */\nfunction useSendAiMessage(\n chatId: string,\n options?: UseSendAiMessageOptions\n): {\n (text: string): AiUserMessage;\n (options: SendAiMessageOptions): AiUserMessage;\n};\n\n/**\n * Returns a function to send a message in an AI chat.\n *\n * @example\n * const sendAiMessage = useSendAiMessage();\n * sendAiMessage({ chatId: \"chat-id\", text: \"Hello, Liveblocks AI!\" });\n *\n * You can set options related to the message being sent, such as the copilot ID to use.\n *\n * @example\n * const sendAiMessage = useSendAiMessage();\n * sendAiMessage({ chatId: \"chat-id\", text: \"Hello, Liveblocks AI!\", copilotId: \"co_xxx\" });\n */\nfunction useSendAiMessage(): (\n options: WithRequired<SendAiMessageOptions, \"chatId\">\n) => AiUserMessage;\n\n/**\n * Returns a function to send a message in an AI chat.\n *\n * @example\n * const sendAiMessage = useSendAiMessage(chatId);\n * sendAiMessage(\"Hello, Liveblocks AI!\");\n *\n * You can set options related to the message being sent, such as the copilot ID to use.\n *\n * @example\n * const sendAiMessage = useSendAiMessage(chatId, { copilotId: \"co_xxx\" });\n * sendAiMessage(\"Hello, Liveblocks AI!\");\n *\n * You can also pass the chat ID dynamically if it's not known when calling the hook.\n *\n * @example\n * const sendAiMessage = useSendAiMessage();\n * sendAiMessage({ chatId: \"chat-id\", text: \"Hello, Liveblocks AI!\" });\n *\n * @example\n * const sendAiMessage = useSendAiMessage();\n * sendAiMessage({ chatId: \"chat-id\", text: \"Hello, Liveblocks AI!\", copilotId: \"co_xxx\" });\n */\nfunction useSendAiMessage(\n chatId?: string,\n options?: UseSendAiMessageOptions\n): {\n (text: string): AiUserMessage;\n (options: SendAiMessageOptions): AiUserMessage;\n (options: WithRequired<SendAiMessageOptions, \"chatId\">): AiUserMessage;\n} {\n const client = useClient();\n\n return useCallback(\n (message: string | SendAiMessageOptions) => {\n const {\n text: messageText,\n chatId: messageOptionsChatId,\n copilotId: messageOptionsCopilotId,\n ...messageOptions\n } = typeof message === \"string\" ? { text: message } : message;\n const resolvedChatId =\n messageOptionsChatId ??\n chatId ??\n // The `useSendAiMessage` overloads prevent this scenario from happening\n // at the type level, and this error prevents it from happening at runtime.\n raise(\n \"chatId must be provided to either `useSendAiMessage` or its returned function.\"\n );\n\n const messages = client[kInternal].ai.signals\n .getChatMessagesForBranchΣ(resolvedChatId)\n .get();\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n !messageOptionsCopilotId &&\n !options?.copilotId\n ) {\n console.warn(\n `No copilot ID was provided to useSendAiMessage when sending the message \"${messageText.slice(\n 0,\n 20\n )}…\". As a result, the message will use the chat's previous copilot ID, which could lead to unexpected behavior.\\nTo ensure the correct copilot ID is used, specify it either through the hook as 'useSendAiMessage(\"${resolvedChatId}\", { copilotId: \"co_xxx\" })' or via the function as 'sendAiMessage({ text: \"${messageText.slice(\n 0,\n 20\n )}…\", copilotId: \"co_xxx\" })'`\n );\n }\n const resolvedCopilotId = (messageOptionsCopilotId ??\n options?.copilotId ??\n client[kInternal].ai.getLastUsedCopilotId(resolvedChatId)) as\n | CopilotId\n | undefined;\n\n const lastMessageId = messages[messages.length - 1]?.id ?? null;\n\n const content = [{ type: \"text\" as const, text: messageText }];\n const newMessageId = client[kInternal].ai[\n kInternal\n ].context.messagesStore.createOptimistically(\n resolvedChatId,\n \"user\",\n lastMessageId,\n content\n );\n const newMessage = client[kInternal].ai[\n kInternal\n ].context.messagesStore.getMessageById(newMessageId) as AiUserMessage;\n\n const targetMessageId = client[kInternal].ai[\n kInternal\n ].context.messagesStore.createOptimistically(\n resolvedChatId,\n \"assistant\",\n newMessageId,\n resolvedCopilotId as CopilotId\n );\n\n void client[kInternal].ai.askUserMessageInChat(\n resolvedChatId,\n { id: newMessageId, parentMessageId: lastMessageId, content },\n targetMessageId,\n {\n stream: messageOptions.stream ?? options?.stream,\n copilotId: resolvedCopilotId,\n timeout: messageOptions.timeout ?? options?.timeout,\n }\n );\n\n return newMessage;\n },\n [client, chatId, options?.copilotId, options?.stream, options?.timeout]\n );\n}\n\n/** @internal */\nexport function createSharedContext<U extends BaseUserMeta>(\n client: Client<U>\n): SharedContextBundle<U> {\n const useClient = () => client;\n\n function useSyncStatus(options?: UseSyncStatusOptions) {\n return useSyncStatus_withClient(client, options);\n }\n\n return {\n classic: {\n useClient,\n useUser: (userId: string) => useUser_withClient(client, userId),\n useRoomInfo: (roomId: string) => useRoomInfo_withClient(client, roomId),\n useGroupInfo: (groupId: string) =>\n useGroupInfo_withClient(client, groupId),\n useIsInsideRoom,\n useErrorListener,\n useSyncStatus,\n RegisterAiKnowledge,\n RegisterAiTool,\n },\n suspense: {\n useClient,\n useUser: (userId: string) => useUserSuspense_withClient(client, userId),\n useRoomInfo: (roomId: string) =>\n useRoomInfoSuspense_withClient(client, roomId),\n useGroupInfo: (groupId: string) =>\n useGroupInfoSuspense_withClient(client, groupId),\n useIsInsideRoom,\n useErrorListener,\n useSyncStatus,\n RegisterAiKnowledge,\n RegisterAiTool,\n },\n };\n}\n\n/**\n * @private This is an internal API.\n */\nfunction useEnsureNoLiveblocksProvider(options?: { allowNesting?: boolean }) {\n const existing = useClientOrNull();\n if (!options?.allowNesting && existing !== null) {\n throw new Error(\n \"You cannot nest multiple LiveblocksProvider instances in the same React tree.\"\n );\n }\n}\n\n/**\n * @private This is a private API.\n */\nexport function LiveblocksProviderWithClient(\n props: PropsWithChildren<{\n client: OpaqueClient;\n\n // Private flag, used only to skip the nesting check if this is\n // a LiveblocksProvider created implicitly by a factory-bound RoomProvider.\n allowNesting?: boolean;\n }>\n) {\n useEnsureNoLiveblocksProvider(props);\n return (\n <ClientContext.Provider value={props.client}>\n {props.children}\n </ClientContext.Provider>\n );\n}\n\n/**\n * Sets up a client for connecting to Liveblocks, and is the recommended way to do\n * this for React apps. You must define either `authEndpoint` or `publicApiKey`.\n * Resolver functions should be placed inside here, and a number of other options\n * are available, which correspond with those passed to `createClient`.\n * Unlike `RoomProvider`, `LiveblocksProvider` doesn’t call Liveblocks servers when mounted,\n * and it should be placed higher in your app’s component tree.\n */\nexport function LiveblocksProvider<U extends BaseUserMeta = DU>(\n props: PropsWithChildren<ClientOptions<U>>\n) {\n const { children, ...o } = props;\n\n // It's important that the static options remain stable, otherwise we'd be\n // creating new client instances on every render.\n const options = {\n publicApiKey: useInitial(o.publicApiKey),\n throttle: useInitial(o.throttle),\n lostConnectionTimeout: useInitial(o.lostConnectionTimeout),\n backgroundKeepAliveTimeout: useInitial(o.backgroundKeepAliveTimeout),\n polyfills: useInitial(o.polyfills),\n largeMessageStrategy: useInitial(o.largeMessageStrategy),\n unstable_streamData: useInitial(o.unstable_streamData),\n preventUnsavedChanges: useInitial(o.preventUnsavedChanges),\n badgeLocation: useInitial(o.badgeLocation),\n\n authEndpoint: useInitialUnlessFunction(o.authEndpoint),\n resolveMentionSuggestions: useInitialUnlessFunction(\n o.resolveMentionSuggestions\n ),\n resolveUsers: useInitialUnlessFunction(o.resolveUsers),\n resolveRoomsInfo: useInitialUnlessFunction(o.resolveRoomsInfo),\n resolveGroupsInfo: useInitialUnlessFunction(o.resolveGroupsInfo),\n\n baseUrl: useInitial(\n // @ts-expect-error - Hidden config options\n o.baseUrl as string | undefined\n ),\n enableDebugLogging: useInitial(\n // @ts-expect-error - Hidden config options\n o.enableDebugLogging as boolean | undefined\n ),\n } as ClientOptions<U>;\n\n // NOTE: Deliberately not passing any deps here, because we'll _never_ want\n // to recreate a client instance after the first render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const client = useMemo(() => createClient<U>(options), []);\n\n // The AI socket is connected to via `useEnsureAiConnection` whenever at least one\n // AI-related hook is used. We only handle disconnecting here when `LiveblocksProvider` unmounts.\n useEffect(() => {\n return () => {\n client[kInternal].ai.disconnect();\n };\n }, [client]);\n\n return (\n <LiveblocksProviderWithClient client={client}>\n {children}\n </LiveblocksProviderWithClient>\n );\n}\n\n/**\n * Creates a LiveblocksProvider and a set of typed hooks. Note that any\n * LiveblocksProvider created in this way takes no props, because it uses\n * settings from the given client instead.\n */\nexport function createLiveblocksContext<\n U extends BaseUserMeta = DU,\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n>(client: OpaqueClient): LiveblocksContextBundle<U, TM, CM> {\n return getOrCreateContextBundle<U, TM, CM>(client);\n}\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n *\n */\nfunction useUserThreads_experimental<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(options: UseUserThreadsOptions<TM> = {}): ThreadsAsyncResult<TM, CM> {\n const client = useClient();\n const { store, userThreadsPoller: poller } = getLiveblocksExtrasForClient<\n TM,\n CM\n >(client);\n const queryKey = makeUserThreadsQueryKey(options.query);\n\n useEffect(\n () =>\n void store.outputs.loadingUserThreads\n .getOrCreate(queryKey)\n .waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => {\n poller.dec();\n };\n }, [poller]);\n\n return useSignal(\n store.outputs.loadingUserThreads.getOrCreate(queryKey).signal\n );\n}\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n */\nfunction useUserThreadsSuspense_experimental<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(options: UseUserThreadsOptions<TM> = {}): ThreadsAsyncSuccess<TM, CM> {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const { store } = getLiveblocksExtrasForClient<TM, CM>(client);\n const queryKey = makeUserThreadsQueryKey(options.query);\n\n use(store.outputs.loadingUserThreads.getOrCreate(queryKey).waitUntilLoaded());\n\n const result = useUserThreads_experimental<TM, CM>(options);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\n/**\n * Returns the inbox notifications for the current user.\n *\n * @example\n * const { inboxNotifications, error, isLoading } = useInboxNotifications();\n */\nfunction useInboxNotifications(options?: UseInboxNotificationsOptions) {\n return useInboxNotifications_withClient(\n useClient(),\n identity,\n shallow,\n options\n );\n}\n\n/**\n * Returns the inbox notifications for the current user.\n *\n * @example\n * const { inboxNotifications } = useInboxNotifications();\n */\nfunction useInboxNotificationsSuspense(options?: UseInboxNotificationsOptions) {\n return useInboxNotificationsSuspense_withClient(useClient(), options);\n}\n\nfunction useInboxNotificationThread<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(inboxNotificationId: string) {\n return useInboxNotificationThread_withClient<TM, CM>(\n useClient(),\n inboxNotificationId\n );\n}\n\n/**\n * Returns a function that marks all of the current user's inbox notifications as read.\n *\n * @example\n * const markAllInboxNotificationsAsRead = useMarkAllInboxNotificationsAsRead();\n * markAllInboxNotificationsAsRead();\n */\nfunction useMarkAllInboxNotificationsAsRead() {\n return useMarkAllInboxNotificationsAsRead_withClient(useClient());\n}\n\n/**\n * Returns a function that marks an inbox notification as read for the current user.\n *\n * @example\n * const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n * markInboxNotificationAsRead(\"in_xxx\");\n */\nfunction useMarkInboxNotificationAsRead() {\n return useMarkInboxNotificationAsRead_withClient(useClient());\n}\n\n/**\n * Returns a function that deletes all of the current user's inbox notifications.\n *\n * @example\n * const deleteAllInboxNotifications = useDeleteAllInboxNotifications();\n * deleteAllInboxNotifications();\n */\nfunction useDeleteAllInboxNotifications() {\n return useDeleteAllInboxNotifications_withClient(useClient());\n}\n\n/**\n * Returns a function that deletes an inbox notification for the current user.\n *\n * @example\n * const deleteInboxNotification = useDeleteInboxNotification();\n * deleteInboxNotification(\"in_xxx\");\n */\nfunction useDeleteInboxNotification() {\n return useDeleteInboxNotification_withClient(useClient());\n}\n\n/**\n * Returns the number of unread inbox notifications for the current user.\n *\n * @example\n * const { count, error, isLoading } = useUnreadInboxNotificationsCount();\n */\nfunction useUnreadInboxNotificationsCount(\n options?: UseInboxNotificationsOptions\n) {\n return useUnreadInboxNotificationsCount_withClient(useClient(), options);\n}\n\n/**\n * Returns the number of unread inbox notifications for the current user.\n *\n * @example\n * const { count } = useUnreadInboxNotificationsCount();\n */\nfunction useUnreadInboxNotificationsCountSuspense(\n options?: UseInboxNotificationsOptions\n) {\n return useUnreadInboxNotificationsCountSuspense_withClient(\n useClient(),\n options\n );\n}\n\n/**\n * Returns notification settings for the current user.\n *\n * @example\n * const [{ settings }, updateNotificationSettings] = useNotificationSettings()\n */\nfunction useNotificationSettings() {\n return useNotificationSettings_withClient(useClient());\n}\n\n/**\n * Returns notification settings for the current user.\n *\n * @example\n * const [{ settings }, updateNotificationSettings] = useNotificationSettings()\n */\nfunction useNotificationSettingsSuspense() {\n return useNotificationSettingsSuspense_withClient(useClient());\n}\n\n/**\n * Returns a function that updates the user's notification\n * settings for a project.\n *\n * @example\n * const updateNotificationSettings = useUpdateNotificationSettings()\n */\nfunction useUpdateNotificationSettings() {\n return useUpdateNotificationSettings_withClient(useClient());\n}\n\nfunction useUser<U extends BaseUserMeta>(userId: string) {\n const client = useClient<U>();\n return useUser_withClient(client, userId);\n}\n\nfunction useUserSuspense<U extends BaseUserMeta>(\n userId: string\n): UserAsyncSuccess<U[\"info\"]> {\n const client = useClient<U>();\n return useUserSuspense_withClient(client, userId);\n}\n\n/**\n * Returns room info from a given room ID.\n *\n * @example\n * const { info, error, isLoading } = useRoomInfo(\"room-id\");\n */\nfunction useRoomInfo(roomId: string): RoomInfoAsyncResult {\n return useRoomInfo_withClient(useClient(), roomId);\n}\n\n/**\n * Returns room info from a given room ID.\n *\n * @example\n * const { info } = useRoomInfo(\"room-id\");\n */\nfunction useRoomInfoSuspense(roomId: string): RoomInfoAsyncSuccess {\n return useRoomInfoSuspense_withClient(useClient(), roomId);\n}\n\n/**\n * Returns group info from a given group ID.\n *\n * @example\n * const { info, error, isLoading } = useGroupInfo(\"group-id\");\n */\nfunction useGroupInfo(groupId: string): GroupInfoAsyncResult {\n return useGroupInfo_withClient(useClient(), groupId);\n}\n\n/**\n * Returns group info from a given group ID.\n *\n * @example\n * const { info } = useGroupInfo(\"group-id\");\n */\nfunction useGroupInfoSuspense(groupId: string): GroupInfoAsyncSuccess {\n return useGroupInfoSuspense_withClient(useClient(), groupId);\n}\n\ntype TypedBundle = LiveblocksContextBundle<DU, DTM, DCM>;\n\n/**\n * Returns the thread associated with a `\"thread\"` inbox notification.\n *\n * It can **only** be called with IDs of `\"thread\"` inbox notifications,\n * so we recommend only using it when customizing the rendering or in other\n * situations where you can guarantee the kind of the notification.\n *\n * When `useInboxNotifications` returns `\"thread\"` inbox notifications,\n * it also receives the associated threads and caches them behind the scenes.\n * When you call `useInboxNotificationThread`, it simply returns the cached thread\n * for the inbox notification ID you passed to it, without any fetching or waterfalls.\n *\n * @example\n * const thread = useInboxNotificationThread(\"in_xxx\");\n */\nconst _useInboxNotificationThread: TypedBundle[\"useInboxNotificationThread\"] =\n useInboxNotificationThread;\n\n/**\n * Returns user info from a given user ID.\n *\n * @example\n * const { user, error, isLoading } = useUser(\"user-id\");\n */\nconst _useUser: TypedBundle[\"useUser\"] = useUser;\n\n/**\n * Returns user info from a given user ID.\n *\n * @example\n * const { user } = useUser(\"user-id\");\n */\nconst _useUserSuspense: TypedBundle[\"suspense\"][\"useUser\"] = useUserSuspense;\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n */\nconst _useUserThreads_experimental: TypedBundle[\"useUserThreads_experimental\"] =\n useUserThreads_experimental;\n\n/**\n * @experimental\n *\n * This hook is experimental and could be removed or changed at any time!\n * Do not use unless explicitly recommended by the Liveblocks team.\n *\n * WARNING:\n * Please note that this hook currently returns all threads by most recently\n * updated threads first. This is inconsistent with the default sort order of\n * the useThreads() hook, which returns them in chronological order (by\n * creation date). In the final version, we will make these hooks behave\n * consistently, so expect that in the final version, you'll have to explicitly\n * specify the sort order to be by most recently updated first somehow.\n * The final API for that is still TBD.\n */\nconst _useUserThreadsSuspense_experimental: TypedBundle[\"suspense\"][\"useUserThreads_experimental\"] =\n useUserThreadsSuspense_experimental;\n\n/**\n * (Private beta) Returns the chats for the current user.\n *\n * @example\n * const { chats, error, isLoading } = useAiChats();\n */\nconst _useAiChats: TypedBundle[\"useAiChats\"] = useAiChats;\n\n/**\n * (Private beta) Returns the chats for the current user.\n *\n * @example\n * const { chats, error, isLoading } = useAiChats();\n */\nconst _useAiChatsSuspense: TypedBundle[\"suspense\"][\"useAiChats\"] =\n useAiChatsSuspense;\n\n/**\n * (Private beta) Returns the information of the given chat.\n *\n * @example\n * const { chat, error, isLoading } = useAiChat(\"my-chat\");\n */\nconst _useAiChat: TypedBundle[\"useAiChat\"] = useAiChat;\n\n/**\n * (Private beta) Returns the information of the given chat.\n *\n * @example\n * const { chat, error, isLoading } = useAiChat(\"my-chat\");\n */\nconst _useAiChatSuspense: TypedBundle[\"suspense\"][\"useAiChat\"] =\n useAiChatSuspense;\n\n/**\n * (Private beta) Returns the messages in the given chat.\n *\n * @example\n * const { messages, error, isLoading } = useAiChatMessages(\"my-chat\");\n */\nconst _useAiChatMessages: TypedBundle[\"useAiChatMessages\"] = useAiChatMessages;\n\n/**\n * (Private beta) Returns the messages in the given chat.\n *\n * @example\n * const { messages, error, isLoading } = useAiChatMessages(\"my-chat\");\n */\nconst _useAiChatMessagesSuspense: TypedBundle[\"suspense\"][\"useAiChatMessages\"] =\n useAiChatMessagesSuspense;\n\n/**\n * Returns metadata for a given URL.\n *\n * @example\n * const { metadata, error, isLoading } = useUrlMetadata(\"https://liveblocks.io\");\n */\nconst _useUrlMetadata: TypedBundle[\"useUrlMetadata\"] = useUrlMetadata;\n\n/**\n * Returns metadata for a given URL.\n *\n * @example\n * const { metadata } = useUrlMetadata(\"https://liveblocks.io\");\n */\nconst _useUrlMetadataSuspense: TypedBundle[\"suspense\"][\"useUrlMetadata\"] =\n useUrlMetadataSuspense;\n\nfunction useSyncStatus_withClient(\n client: OpaqueClient,\n options?: UseSyncStatusOptions\n): SyncStatus {\n // Normally the Rules of Hooks™ dictate that you should not call hooks\n // conditionally. In this case, we're good here, because the same code path\n // will always be taken on every subsequent render here, because we've frozen\n // the value.\n /* eslint-disable react-hooks/rules-of-hooks */\n const smooth = useInitial(options?.smooth ?? false);\n if (smooth) {\n return useSyncStatusSmooth_withClient(client);\n } else {\n return useSyncStatusImmediate_withClient(client);\n }\n /* eslint-enable react-hooks/rules-of-hooks */\n}\n\nfunction useSyncStatusImmediate_withClient(client: OpaqueClient): SyncStatus {\n return useSyncExternalStore(\n client.events.syncStatus.subscribe,\n client.getSyncStatus,\n client.getSyncStatus\n );\n}\n\nfunction useSyncStatusSmooth_withClient(client: OpaqueClient): SyncStatus {\n const getter = client.getSyncStatus;\n const [status, setStatus] = useState(getter);\n const oldStatus = useLatest(getter());\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout>;\n const unsub = client.events.syncStatus.subscribe(() => {\n const newStatus = getter();\n if (\n oldStatus.current === \"synchronizing\" &&\n newStatus === \"synchronized\"\n ) {\n // Delay delivery of the \"synchronized\" event\n timeoutId = setTimeout(() => setStatus(newStatus), config.SMOOTH_DELAY);\n } else {\n clearTimeout(timeoutId);\n setStatus(newStatus);\n }\n });\n\n // Clean up\n return () => {\n clearTimeout(timeoutId);\n unsub();\n };\n }, [client, getter, oldStatus]);\n\n return status;\n}\n\n/**\n * Returns the current Liveblocks sync status, and triggers a re-render\n * whenever it changes. Can be used to render a \"Saving...\" indicator, or for\n * preventing that a browser tab can be closed until all changes have been\n * synchronized with the server.\n *\n * @example\n * const syncStatus = useSyncStatus(); // \"synchronizing\" | \"synchronized\"\n * const syncStatus = useSyncStatus({ smooth: true });\n */\nfunction useSyncStatus(options?: UseSyncStatusOptions): SyncStatus {\n return useSyncStatus_withClient(useClient(), options);\n}\n\n/**\n * useErrorListener is a React hook that allows you to respond to any\n * Liveblocks error, for example room connection errors, errors\n * creating/editing/deleting threads, etc.\n *\n * @example\n * useErrorListener(err => {\n * console.error(err);\n * })\n */\nfunction useErrorListener(callback: (err: LiveblocksError) => void): void {\n const client = useClient();\n const savedCallback = useLatest(callback);\n useEffect(\n () => client.events.error.subscribe((e) => savedCallback.current(e)),\n [client, savedCallback]\n );\n}\n\n// eslint-disable-next-line simple-import-sort/exports\nexport {\n _useInboxNotificationThread as useInboxNotificationThread,\n _useUser as useUser,\n _useUserSuspense as useUserSuspense,\n useInboxNotifications,\n useInboxNotificationsSuspense,\n useMarkAllInboxNotificationsAsRead,\n useMarkInboxNotificationAsRead,\n useDeleteAllInboxNotifications,\n useDeleteInboxNotification,\n useErrorListener,\n useRoomInfo,\n useRoomInfoSuspense,\n useGroupInfo,\n useGroupInfoSuspense,\n useSyncStatus,\n useUnreadInboxNotificationsCount,\n useUnreadInboxNotificationsCountSuspense,\n useNotificationSettings,\n useNotificationSettingsSuspense,\n useUpdateNotificationSettings,\n _useUserThreads_experimental as useUserThreads_experimental,\n _useUserThreadsSuspense_experimental as useUserThreadsSuspense_experimental,\n _useAiChats as useAiChats,\n _useAiChatsSuspense as useAiChatsSuspense,\n _useAiChat as useAiChat,\n _useAiChatSuspense as useAiChatSuspense,\n _useAiChatMessages as useAiChatMessages,\n _useAiChatMessagesSuspense as useAiChatMessagesSuspense,\n useAiChatStatus,\n useCreateAiChat,\n useDeleteAiChat,\n useSendAiMessage,\n _useUrlMetadata as useUrlMetadata,\n _useUrlMetadataSuspense as useUrlMetadataSuspense,\n};\n","const SECONDS = 1000;\nconst MINUTES = 60 * SECONDS;\n\n// Poller config\nexport const config = {\n SMOOTH_DELAY: 1 * SECONDS,\n\n NOTIFICATIONS_POLL_INTERVAL: 1 * MINUTES,\n NOTIFICATIONS_MAX_STALE_TIME: 5 * SECONDS,\n\n ROOM_THREADS_POLL_INTERVAL: 5 * MINUTES,\n ROOM_THREADS_MAX_STALE_TIME: 5 * SECONDS,\n\n USER_THREADS_POLL_INTERVAL: 1 * MINUTES,\n USER_THREADS_MAX_STALE_TIME: 30 * SECONDS,\n\n HISTORY_VERSIONS_POLL_INTERVAL: 1 * MINUTES,\n HISTORY_VERSIONS_MAX_STALE_TIME: 5 * SECONDS,\n\n ROOM_SUBSCRIPTION_SETTINGS_POLL_INTERVAL: 1 * MINUTES,\n ROOM_SUBSCRIPTION_SETTINGS_MAX_STALE_TIME: 5 * SECONDS,\n\n USER_NOTIFICATION_SETTINGS_INTERVAL: 5 * MINUTES,\n USER_NOTIFICATION_SETTINGS_MAX_STALE_TIME: 1 * MINUTES,\n};\n","import type { AsyncError, AsyncLoading, AsyncSuccess } from \"@liveblocks/core\";\n\n// TODO Maybe move these into @liveblocks/core if they are useful?\n\nexport const ASYNC_LOADING: AsyncLoading = Object.freeze({ isLoading: true });\n\nexport const ASYNC_ERR = (error: Error): AsyncError =>\n Object.freeze({ isLoading: false, error });\n\nexport function ASYNC_OK<T>(data: T): AsyncSuccess<T>;\nexport function ASYNC_OK<T, F extends string>(\n field: F,\n data: T\n): AsyncSuccess<T, F>;\nexport function ASYNC_OK<T, F extends string>(\n fieldOrData: F | T,\n data?: T\n): AsyncSuccess<T, F> {\n if (arguments.length === 1) {\n // @ts-expect-error too dynamic to type\n return Object.freeze({ isLoading: false, data: fieldOrData });\n } else {\n // @ts-expect-error too dynamic to type\n return Object.freeze({ isLoading: false, [fieldOrData as F]: data });\n }\n}\n","export function ensureNotServerSide(): void {\n // Error early if suspense is used in a server-side context\n if (typeof window === \"undefined\") {\n throw new Error(\n \"You cannot use the Suspense version of Liveblocks hooks server side. Make sure to only call them client side by using a ClientSideSuspense wrapper.\\nFor tips, see https://liveblocks.io/docs/api-reference/liveblocks-react#ClientSideSuspense\"\n );\n }\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { useLatest } from \"./use-latest\";\n\n/**\n * \"Freezes\" a given value, so that it will return the same value/instance on\n * each subsequent render. This can be used to freeze \"initial\" values for\n * custom hooks, much like how `useState(initialState)` or\n * `useRef(initialValue)` works.\n */\nexport function useInitial<T>(value: T, roomId?: string): T {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => value, [roomId]);\n}\n\n/**\n * Like `useInitial`, but if the provided value is a function instance, will\n * instead return a stable wrapper that _is_ a stable reference itself between\n * re-renders, but one which will always call the _latest_ provided callback\n * instance.\n */\nexport function useInitialUnlessFunction<T>(\n latestValue: T,\n roomId?: string\n): T {\n const frozenValue = useInitial(latestValue, roomId);\n\n type Fn = T & ((...args: unknown[]) => unknown);\n const ref = useLatest(latestValue as Fn);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const wrapper = useCallback(\n ((...args: unknown[]) => ref.current(...args)) as Fn,\n [ref]\n );\n\n // Return the wrapper only if the frozen value is a function\n if (typeof frozenValue === \"function\") {\n return wrapper;\n } else {\n return frozenValue;\n }\n}\n","import * as React from \"react\";\n\ntype Use = <T>(promise: Promise<T>) => T;\n\n// Prevent bundlers from trying to `import { use } from \"react\";`\nconst reactUse = React[\" use \".trim().toString() as keyof typeof React] as\n | Use\n | undefined;\n\n/**\n * Drop-in replacement for React 19's `use` hook,\n * with a partial polyfill for older versions of React.\n *\n * ⚠️ Only supports `use(promise)`, not `use(context)`.\n */\nexport const use =\n reactUse ??\n (<T>(\n promise: Promise<T> & {\n status?: \"pending\" | \"fulfilled\" | \"rejected\";\n value?: T;\n reason?: unknown;\n }\n ): T => {\n if (promise.status === \"pending\") {\n throw promise;\n } else if (promise.status === \"fulfilled\") {\n return promise.value as T;\n } else if (promise.status === \"rejected\") {\n throw promise.reason;\n } else {\n promise.status = \"pending\";\n promise.then(\n (v) => {\n promise.status = \"fulfilled\";\n promise.value = v;\n },\n (e) => {\n promise.status = \"rejected\";\n promise.reason = e;\n }\n );\n throw promise;\n }\n });\n","import type {\n AiChatsQuery,\n AsyncResult,\n BaseMetadata,\n BaseUserMeta,\n Client,\n CommentData,\n CommentReaction,\n CommentUserReaction,\n Cursor,\n DistributiveOmit,\n HistoryVersion,\n InboxNotificationData,\n InboxNotificationDeleteInfo,\n ISignal,\n MessageId,\n NotificationSettings,\n OpaqueClient,\n PartialNotificationSettings,\n Patchable,\n Permission,\n Resolve,\n RoomSubscriptionSettings,\n SubscriptionData,\n SubscriptionDeleteInfo,\n SubscriptionKey,\n ThreadData,\n ThreadDataWithDeleteInfo,\n ThreadDeleteInfo,\n UrlMetadata,\n} from \"@liveblocks/core\";\nimport {\n assertNever,\n autoRetry,\n batch,\n compactObject,\n console,\n createNotificationSettings,\n DefaultMap,\n DerivedSignal,\n getSubscriptionKey,\n kInternal,\n MutableSignal,\n nanoid,\n nn,\n patchNotificationSettings,\n shallow,\n shallow2,\n Signal,\n stableStringify,\n} from \"@liveblocks/core\";\n\nimport { ASYNC_ERR, ASYNC_LOADING, ASYNC_OK } from \"./lib/AsyncResult\";\nimport { autobind } from \"./lib/autobind\";\nimport { find } from \"./lib/itertools\";\nimport { makeInboxNotificationsFilter } from \"./lib/querying\";\nimport type { ReadonlyThreadDB } from \"./ThreadDB\";\nimport { ThreadDB } from \"./ThreadDB\";\nimport type {\n AiChatAsyncResult,\n AiChatMessagesAsyncResult,\n AiChatsAsyncResult,\n HistoryVersionsAsyncResult,\n InboxNotificationsAsyncResult,\n InboxNotificationsQuery,\n NotificationSettingsAsyncResult,\n RoomSubscriptionSettingsAsyncResult,\n ThreadsAsyncResult,\n ThreadsQuery,\n UnreadInboxNotificationsCountAsyncResult,\n UrlMetadataAsyncResult,\n} from \"./types\";\n\ntype OptimisticUpdate<TM extends BaseMetadata, CM extends BaseMetadata> =\n | CreateThreadOptimisticUpdate<TM, CM>\n | DeleteThreadOptimisticUpdate\n | EditThreadMetadataOptimisticUpdate<TM>\n | MarkThreadAsResolvedOptimisticUpdate\n | MarkThreadAsUnresolvedOptimisticUpdate\n | SubscribeToThreadOptimisticUpdate\n | UnsubscribeFromThreadOptimisticUpdate\n | CreateCommentOptimisticUpdate<CM>\n | EditCommentOptimisticUpdate<CM>\n | EditCommentMetadataOptimisticUpdate<CM>\n | DeleteCommentOptimisticUpdate\n | AddReactionOptimisticUpdate\n | RemoveReactionOptimisticUpdate\n | MarkInboxNotificationAsReadOptimisticUpdate\n | MarkAllInboxNotificationsAsReadOptimisticUpdate\n | DeleteInboxNotificationOptimisticUpdate\n | DeleteAllInboxNotificationsOptimisticUpdate\n | UpdateRoomSubscriptionSettingsOptimisticUpdate\n | UpdateNotificationSettingsOptimisticUpdate;\n\ntype CreateThreadOptimisticUpdate<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n type: \"create-thread\";\n id: string;\n roomId: string;\n thread: ThreadData<TM, CM>;\n};\n\ntype DeleteThreadOptimisticUpdate = {\n type: \"delete-thread\";\n id: string;\n roomId: string;\n threadId: string;\n deletedAt: Date;\n};\n\ntype EditThreadMetadataOptimisticUpdate<TM extends BaseMetadata> = {\n type: \"edit-thread-metadata\";\n id: string;\n threadId: string;\n metadata: Resolve<Patchable<TM>>;\n updatedAt: Date;\n};\n\ntype MarkThreadAsResolvedOptimisticUpdate = {\n type: \"mark-thread-as-resolved\";\n id: string;\n threadId: string;\n updatedAt: Date;\n};\n\ntype MarkThreadAsUnresolvedOptimisticUpdate = {\n type: \"mark-thread-as-unresolved\";\n id: string;\n threadId: string;\n updatedAt: Date;\n};\n\ntype SubscribeToThreadOptimisticUpdate = {\n type: \"subscribe-to-thread\";\n id: string;\n threadId: string;\n subscribedAt: Date;\n};\n\ntype UnsubscribeFromThreadOptimisticUpdate = {\n type: \"unsubscribe-from-thread\";\n id: string;\n threadId: string;\n unsubscribedAt: Date;\n};\n\ntype CreateCommentOptimisticUpdate<CM extends BaseMetadata> = {\n type: \"create-comment\";\n id: string;\n comment: CommentData<CM>;\n};\n\ntype EditCommentOptimisticUpdate<CM extends BaseMetadata> = {\n type: \"edit-comment\";\n id: string;\n comment: CommentData<CM>;\n};\n\ntype EditCommentMetadataOptimisticUpdate<CM extends BaseMetadata> = {\n type: \"edit-comment-metadata\";\n id: string;\n threadId: string;\n commentId: string;\n metadata: Resolve<Patchable<CM>>;\n updatedAt: Date;\n};\n\ntype DeleteCommentOptimisticUpdate = {\n type: \"delete-comment\";\n id: string;\n roomId: string;\n threadId: string;\n deletedAt: Date;\n commentId: string;\n};\n\ntype AddReactionOptimisticUpdate = {\n type: \"add-reaction\";\n id: string;\n threadId: string;\n commentId: string;\n reaction: CommentUserReaction;\n};\n\ntype RemoveReactionOptimisticUpdate = {\n type: \"remove-reaction\";\n id: string;\n threadId: string;\n commentId: string;\n emoji: string;\n userId: string;\n removedAt: Date;\n};\n\ntype MarkInboxNotificationAsReadOptimisticUpdate = {\n type: \"mark-inbox-notification-as-read\";\n id: string;\n inboxNotificationId: string;\n readAt: Date;\n};\n\ntype MarkAllInboxNotificationsAsReadOptimisticUpdate = {\n type: \"mark-all-inbox-notifications-as-read\";\n id: string;\n readAt: Date;\n};\n\ntype DeleteInboxNotificationOptimisticUpdate = {\n type: \"delete-inbox-notification\";\n id: string;\n inboxNotificationId: string;\n deletedAt: Date;\n};\n\ntype DeleteAllInboxNotificationsOptimisticUpdate = {\n type: \"delete-all-inbox-notifications\";\n id: string;\n deletedAt: Date;\n};\n\ntype UpdateRoomSubscriptionSettingsOptimisticUpdate = {\n type: \"update-room-subscription-settings\";\n id: string;\n roomId: string;\n userId: string;\n settings: Partial<RoomSubscriptionSettings>;\n};\n\ntype UpdateNotificationSettingsOptimisticUpdate = {\n type: \"update-notification-settings\";\n id: string;\n settings: PartialNotificationSettings;\n};\n\ntype PaginationState = {\n cursor: string | null; // If `null`, it's the last page\n hasFetchedAll: boolean;\n isFetchingMore: boolean;\n fetchMoreError?: Error;\n fetchMore: () => void;\n};\n\n/**\n * Valid combinations of field patches to the pagination state.\n */\ntype PaginationStatePatch =\n | { isFetchingMore: true }\n | {\n hasFetchedAll: boolean;\n isFetchingMore: false;\n cursor: string | null;\n fetchMoreError: undefined;\n }\n | { isFetchingMore: false; fetchMoreError: Error };\n\n/**\n * Example:\n * makeRoomThreadsQueryKey('room-abc', { xyz: 123, abc: \"red\" })\n * → '[\"room-abc\",{\"color\":\"red\",\"xyz\":123}]'\n */\nexport function makeRoomThreadsQueryKey<TM extends BaseMetadata>(\n roomId: string,\n query: ThreadsQuery<TM> | undefined\n) {\n return stableStringify([roomId, query ?? {}]);\n}\n\nexport function makeUserThreadsQueryKey<TM extends BaseMetadata>(\n query: ThreadsQuery<TM> | undefined\n) {\n return stableStringify(query ?? {});\n}\n\nexport function makeAiChatsQueryKey(\n query: AiChatsQuery | undefined\n): AiChatsQueryKey {\n return stableStringify(query ?? {});\n}\n\nexport function makeInboxNotificationsQueryKey(\n query: InboxNotificationsQuery | undefined\n) {\n return stableStringify(query ?? {});\n}\n\n/**\n * Like Promise<T>, except it will have a synchronously readable `status`\n * field, indicating the status of the promise.\n * This is compatible with React's `use()` promises, hence the name.\n */\ntype UsablePromise<T> = Promise<T> &\n (\n | { status: \"pending\" }\n | { status: \"rejected\"; reason: Error }\n | { status: \"fulfilled\"; value: T }\n );\n\n/**\n * Given any Promise<T>, monkey-patches it to a UsablePromise<T>, whose\n * asynchronous status can be synchronously observed.\n */\nfunction usify<T>(promise: Promise<T>): UsablePromise<T> {\n if (\"status\" in promise) {\n // Already a usable promise\n return promise as UsablePromise<T>;\n }\n\n const usable: UsablePromise<T> = promise as UsablePromise<T>;\n usable.status = \"pending\";\n usable.then(\n (value) => {\n usable.status = \"fulfilled\";\n (usable as UsablePromise<T> & { status: \"fulfilled\" }).value = value;\n },\n (err) => {\n usable.status = \"rejected\";\n (usable as UsablePromise<T> & { status: \"rejected\" }).reason =\n err as Error;\n }\n );\n return usable;\n}\n\nconst noop = Promise.resolve();\n\n/**\n * The PaginatedResource helper class is responsible for and abstracts away the\n * following:\n *\n * - It receives a \"page fetch\" function of the following signature:\n * (cursor?: Cursor) => Promise<Cursor | null>\n *\n * - Note that there is no data in the returned value!!! Storing or handling\n * the data is NOT the responsibility of this helper class. This may be a bit\n * counter-intuitive at first. The provided page fetcher callback function\n * should store the data elsewhere, outside of the PaginatedResource state\n * machine, as a side-effect of this \"page fetch\" function, but it can always\n * assume the happy path. This class will deal with all the required\n * complexity for handling the non-happy path conditions.\n *\n * - This class exposes a \"getter\" that you can call synchronously to get the\n * current fetching/paginationo status for this resource. It will look like\n * the pagination hooks, except it will not contain any data. In other words,\n * it can return any of these shapes:\n *\n * - { isLoading: true }\n * - {\n * isLoading: false,\n * error: new Error('error while fetching'),\n * }\n * - {\n * isLoading: false,\n * data: {\n * cursor: string | null;\n * isFetchingMore: boolean;\n * fetchMoreError?: Error;\n * }\n * }\n *\n * - When calling the getter multiple times, the return value is always\n * referentially equal to the previous call.\n *\n * - When in this error state, the error will remain in error state for\n * 5 seconds. After those 5 seconds, the resource status gets reset, and the\n * next time the \"getter\" is accessed, the resource will re-initiate the\n * initial fetching process.\n *\n * - This class exposes an Observable that is notified whenever the state\n * changes. For now, this observable can be used to call a no-op update to\n * the Store (eg `.set(state => ({...state})`), to trigger a re-render for\n * all React components.\n *\n * - This class will also expose a function that can be exposed as the\n * `fetchMore` function which can be called externally.\n *\n * - This nicely bundles the internal state that should always be mutated\n * together to manage all the pagination state.\n *\n * - For InboxNotifications we will have one instance of this class.\n *\n * - For Threads we will have one for each query.\n *\n * ---------------------------------------------------------------------------\n *\n * NOT 100% SURE ABOUT THE FOLLOWING YET:\n *\n * - Maybe we could eventually also let this manage the \"delta updates\" and the\n * \"last requested at\" for this resource? Seems nice to add it here somehow.\n * Need to think about the exact implications though.\n *\n * @internal Only exported for unit tests.\n */\nexport class PaginatedResource {\n readonly #signal: Signal<AsyncResult<PaginationState>>;\n public readonly signal: ISignal<AsyncResult<PaginationState>>;\n\n #fetchPage: (cursor?: string) => Promise<string | null>;\n #pendingFetchMore: Promise<void> | null;\n\n constructor(fetchPage: (cursor?: string) => Promise<string | null>) {\n this.#signal = new Signal<AsyncResult<PaginationState>>(ASYNC_LOADING);\n this.#fetchPage = fetchPage;\n this.#pendingFetchMore = null;\n this.signal = this.#signal.asReadonly();\n\n autobind(this);\n }\n\n get(): AsyncResult<PaginationState> {\n return this.#signal.get();\n }\n\n #patch(patch: PaginationStatePatch): void {\n const state = this.#signal.get();\n if (state.data === undefined) return;\n this.#signal.set(ASYNC_OK({ ...state.data, ...patch }));\n }\n\n async #fetchMore(): Promise<void> {\n const state = this.#signal.get();\n if (!state.data?.cursor || state.data.isFetchingMore) {\n // Either:\n // - We don't have a cursor yet (first fetch not happened successfully yet)\n // - We don't have a cursor any longer (we're on the last page)\n return;\n }\n\n this.#patch({ isFetchingMore: true });\n try {\n const nextCursor = await this.#fetchPage(state.data.cursor);\n this.#patch({\n cursor: nextCursor,\n hasFetchedAll: nextCursor === null,\n fetchMoreError: undefined,\n isFetchingMore: false,\n });\n } catch (err) {\n this.#patch({\n isFetchingMore: false,\n fetchMoreError: err as Error,\n });\n }\n }\n\n public fetchMore(): Promise<void> {\n // We do not proceed with fetching more if any of the following is true:\n // 1) the pagination state has not be initialized\n // 2) the cursor is null, i.e., there are no more pages to fetch\n // 3) a request to fetch more is currently in progress\n const state = this.#signal.get();\n if (!state.data?.cursor) return noop;\n\n // Case (3)\n if (!this.#pendingFetchMore) {\n this.#pendingFetchMore = this.#fetchMore().finally(() => {\n this.#pendingFetchMore = null;\n });\n }\n return this.#pendingFetchMore;\n }\n\n #cachedPromise: UsablePromise<void> | null = null;\n\n public waitUntilLoaded(): UsablePromise<void> {\n if (this.#cachedPromise) {\n return this.#cachedPromise;\n }\n\n // Wrap the request to load room threads (and notifications) in an auto-retry function so that if the request fails,\n // we retry for at most 5 times with incremental backoff delays. If all retries fail, the auto-retry function throws an error\n const initialPageFetch$ = autoRetry(\n () => this.#fetchPage(/* cursor */ undefined),\n 5,\n [5000, 5000, 10000, 15000]\n );\n\n const promise = usify(initialPageFetch$);\n\n // NOTE: However tempting it may be, we cannot simply move this block into\n // the promise definition above. The reason is that we should not call\n // notify() before the UsablePromise is actually in resolved status. While\n // still inside the .then() block, the UsablePromise is still in pending status.\n promise.then(\n (cursor) => {\n this.#signal.set(\n ASYNC_OK({\n cursor,\n hasFetchedAll: cursor === null,\n isFetchingMore: false,\n fetchMoreError: undefined,\n fetchMore: this.fetchMore,\n })\n );\n },\n (err) => {\n this.#signal.set(ASYNC_ERR(err as Error));\n\n // Wait for 5 seconds before removing the request\n setTimeout(() => {\n this.#cachedPromise = null;\n this.#signal.set(ASYNC_LOADING);\n }, 5_000);\n }\n );\n\n this.#cachedPromise =\n promise as UsablePromise<unknown> as UsablePromise<void>;\n return this.#cachedPromise;\n }\n}\n\n// TODO Find better name?\ntype LoadableResource<T> = {\n signal: ISignal<T>;\n waitUntilLoaded: () => UsablePromise<void>;\n};\n\nclass SinglePageResource {\n readonly #signal: Signal<AsyncResult<void>>;\n public readonly signal: ISignal<AsyncResult<void>>;\n\n #fetchPage: () => Promise<void>;\n\n #autoRetry: boolean = true;\n\n constructor(fetchPage: () => Promise<void>, autoRetry: boolean = true) {\n this.#signal = new Signal<AsyncResult<void>>(ASYNC_LOADING);\n this.signal = this.#signal.asReadonly();\n this.#fetchPage = fetchPage;\n this.#autoRetry = autoRetry;\n\n autobind(this);\n }\n\n get(): AsyncResult<void> {\n return this.#signal.get();\n }\n\n #cachedPromise: UsablePromise<void> | null = null;\n\n public waitUntilLoaded(): UsablePromise<void> {\n if (this.#cachedPromise) {\n return this.#cachedPromise;\n }\n\n // Wrap the request to load room threads (and notifications) in an auto-retry function so that if the request fails,\n // we retry for at most 5 times with incremental backoff delays. If all retries fail, the auto-retry function throws an error\n const initialFetcher$ = this.#autoRetry\n ? autoRetry(() => this.#fetchPage(), 5, [5000, 5000, 10000, 15000])\n : this.#fetchPage();\n\n const promise = usify(initialFetcher$);\n\n // NOTE: However tempting it may be, we cannot simply move this block into\n // the promise definition above. The reason is that we should not call\n // notify() before the UsablePromise is actually in resolved status. While\n // still inside the .then() block, the UsablePromise is still in pending status.\n promise.then(\n () => {\n this.#signal.set(ASYNC_OK(undefined));\n },\n (err) => {\n this.#signal.set(ASYNC_ERR(err as Error));\n\n if (this.#autoRetry) {\n // Wait for 5 seconds before removing the request\n setTimeout(() => {\n this.#cachedPromise = null;\n this.#signal.set(ASYNC_LOADING);\n }, 5_000);\n }\n }\n );\n\n this.#cachedPromise = promise;\n return promise;\n }\n}\n\ntype RoomId = string;\ntype UserQueryKey = string;\ntype RoomQueryKey = string;\ntype InboxNotificationsQueryKey = string;\n\ntype AiChatsQueryKey = string;\n\n/**\n * A lookup table (LUT) for all the history versions.\n */\ntype VersionsLUT = DefaultMap<RoomId, Map<string, HistoryVersion>>;\n\n/**\n * A lookup table (LUT) for all the inbox notifications.\n */\ntype NotificationsLUT = Map<string, InboxNotificationData>;\n\n/**\n * A lookup table (LUT) for all the unread inbox notifications count.\n */\ntype UnreadInboxNotificationsCountLUT = Map<string, number>;\n\n/**\n * A lookup table (LUT) for all the subscriptions.\n */\ntype SubscriptionsLUT = Map<SubscriptionKey, SubscriptionData>;\n\n/**\n * A lookup table (LUT) for all the room subscription settings.\n */\ntype RoomSubscriptionSettingsLUT = Map<RoomId, RoomSubscriptionSettings>;\n\n/**\n * Room subscription settings by room ID.\n * e.g. { 'room-abc': { threads: \"all\" },\n * 'room-def': { threads: \"replies_and_mentions\" },\n * 'room-xyz': { threads: \"none\" },\n * }\n */\ntype RoomSubscriptionSettingsByRoomId = Record<\n RoomId,\n RoomSubscriptionSettings\n>;\n\nexport type SubscriptionsByKey = Record<SubscriptionKey, SubscriptionData>;\n\nexport type CleanThreadifications<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> =\n // Threads + Notifications = Threadifications\n CleanThreads<TM, CM> &\n //\n CleanNotifications;\n\nexport type CleanThreads<TM extends BaseMetadata, CM extends BaseMetadata> = {\n /**\n * Keep track of loading and error status of all the queries made by the client.\n * e.g. 'room-abc-{\"color\":\"red\"}' - ok\n * e.g. 'room-abc-{}' - loading\n */\n threadsDB: ReadonlyThreadDB<TM, CM>;\n};\n\nexport type CleanNotifications = {\n /**\n * All inbox notifications in a sorted array, optimistic updates applied.\n */\n sortedNotifications: InboxNotificationData[];\n\n /**\n * Inbox notifications by ID.\n * e.g. `in_${string}`\n */\n notificationsById: Record<string, InboxNotificationData>;\n};\n\nexport type CleanThreadSubscriptions = {\n /**\n * Thread subscriptions by key (kind + subject ID).\n * e.g. `thread:${string}`, `$custom:${string}`, etc\n */\n subscriptions: SubscriptionsByKey;\n\n /**\n * All inbox notifications in a sorted array, optimistic updates applied.\n *\n * `useThreadSubscription` returns the subscription status based on subscriptions\n * but also the `readAt` value of the associated notification, so we need to\n * expose the notifications here as well.\n */\n notifications: InboxNotificationData[];\n};\n\nfunction createStore_forNotifications() {\n const signal = new MutableSignal<NotificationsLUT>(new Map());\n\n function markRead(notificationId: string, readAt: Date) {\n signal.mutate((lut) => {\n const existing = lut.get(notificationId);\n if (!existing) {\n return false;\n }\n lut.set(notificationId, { ...existing, readAt });\n return true;\n });\n }\n\n function markAllRead(readAt: Date) {\n signal.mutate((lut) => {\n for (const n of lut.values()) {\n n.readAt = readAt;\n }\n });\n }\n\n function deleteOne(inboxNotificationId: string) {\n signal.mutate((lut) => lut.delete(inboxNotificationId));\n }\n\n function clear() {\n signal.mutate((lut) => lut.clear());\n }\n\n function applyDelta(\n newNotifications: InboxNotificationData[],\n deletedNotifications: InboxNotificationDeleteInfo[]\n ) {\n signal.mutate((lut) => {\n let mutated = false;\n\n // Add new notifications or update existing notifications if the existing notification is older than the new notification.\n for (const n of newNotifications) {\n const existing = lut.get(n.id);\n // If the notification already exists, we need to compare the two notifications to determine which one is newer.\n if (existing) {\n const result = compareInboxNotifications(existing, n);\n // If the existing notification is newer than the new notification, we do not update the existing notification.\n if (result === 1) continue;\n }\n\n // If the new notification is newer than the existing notification, we update the existing notification.\n lut.set(n.id, n);\n mutated = true;\n }\n\n for (const n of deletedNotifications) {\n lut.delete(n.id);\n mutated = true;\n }\n return mutated;\n });\n }\n\n function updateAssociatedNotification<CM extends BaseMetadata>(\n newComment: CommentData<CM>\n ) {\n signal.mutate((lut) => {\n const existing = find(\n lut.values(),\n (notification) =>\n notification.kind === \"thread\" &&\n notification.threadId === newComment.threadId\n );\n if (!existing) return false; // Nothing to udate here\n\n // If the thread has an inbox notification associated with it, we update the notification's `notifiedAt` and `readAt` values\n lut.set(existing.id, {\n ...existing,\n notifiedAt: newComment.createdAt,\n readAt: newComment.createdAt,\n });\n return true;\n });\n }\n\n function upsert(notification: InboxNotificationData) {\n signal.mutate((lut) => {\n lut.set(notification.id, notification);\n });\n }\n\n return {\n signal: signal.asReadonly(),\n\n // Mutations\n markAllRead,\n markRead,\n delete: deleteOne,\n applyDelta,\n clear,\n updateAssociatedNotification,\n upsert,\n };\n}\n\nfunction createStore_forUnreadNotificationsCount() {\n const baseSignal = new MutableSignal<UnreadInboxNotificationsCountLUT>(\n new Map()\n );\n\n function update(queryKey: InboxNotificationsQueryKey, count: number): void {\n baseSignal.mutate((lut) => {\n lut.set(queryKey, count);\n });\n }\n\n return {\n signal: DerivedSignal.from(baseSignal, (c) => Object.fromEntries(c)),\n\n // Mutations\n update,\n };\n}\n\nfunction createStore_forSubscriptions(\n updates: ISignal<readonly OptimisticUpdate<BaseMetadata, BaseMetadata>[]>,\n threads: ReadonlyThreadDB<BaseMetadata, BaseMetadata>\n) {\n const baseSignal = new MutableSignal<SubscriptionsLUT>(new Map());\n\n function applyDelta(\n newSubscriptions: SubscriptionData[],\n deletedSubscriptions: SubscriptionDeleteInfo[]\n ) {\n baseSignal.mutate((lut) => {\n let mutated = false;\n\n for (const s of newSubscriptions) {\n lut.set(getSubscriptionKey(s), s);\n mutated = true;\n }\n\n for (const s of deletedSubscriptions) {\n lut.delete(getSubscriptionKey(s));\n mutated = true;\n }\n\n return mutated;\n });\n }\n\n function create(subscription: SubscriptionData) {\n baseSignal.mutate((lut) => {\n lut.set(getSubscriptionKey(subscription), subscription);\n });\n }\n\n function deleteOne(subscriptionKey: SubscriptionKey) {\n baseSignal.mutate((lut) => {\n lut.delete(subscriptionKey);\n });\n }\n\n return {\n signal: DerivedSignal.from(baseSignal, updates, (base, updates) =>\n applyOptimisticUpdates_forSubscriptions(base, threads, updates)\n ),\n\n // Mutations\n applyDelta,\n create,\n delete: deleteOne,\n };\n}\n\nfunction createStore_forRoomSubscriptionSettings(\n updates: ISignal<readonly OptimisticUpdate<BaseMetadata, BaseMetadata>[]>\n) {\n const baseSignal = new MutableSignal<RoomSubscriptionSettingsLUT>(new Map());\n\n function update(roomId: string, settings: RoomSubscriptionSettings): void {\n baseSignal.mutate((lut) => {\n lut.set(roomId, settings);\n });\n }\n\n return {\n signal: DerivedSignal.from(baseSignal, updates, (base, updates) =>\n applyOptimisticUpdates_forRoomSubscriptionSettings(base, updates)\n ),\n\n // Mutations\n update,\n };\n}\n\nfunction createStore_forHistoryVersions() {\n const baseSignal = new MutableSignal(\n new DefaultMap(() => new Map()) as VersionsLUT\n );\n\n function update(roomId: string, versions: HistoryVersion[]): void {\n baseSignal.mutate((lut) => {\n const versionsById = lut.getOrCreate(roomId);\n for (const version of versions) {\n versionsById.set(version.id, version);\n }\n });\n }\n\n return {\n signal: DerivedSignal.from(baseSignal, (hv) =>\n Object.fromEntries(\n [...hv].map(([roomId, versions]) => [\n roomId,\n Object.fromEntries(versions),\n ])\n )\n ),\n\n // Mutations\n update,\n };\n}\n\nfunction createStore_forUrlsMetadata() {\n const baseSignal = new MutableSignal<Map<string, UrlMetadata>>(new Map());\n\n function update(url: string, metadata: UrlMetadata): void {\n baseSignal.mutate((lut) => {\n lut.set(url, metadata);\n });\n }\n\n return {\n signal: DerivedSignal.from(baseSignal, (m) => Object.fromEntries(m)),\n\n // Mutations\n update,\n };\n}\n\nfunction createStore_forPermissionHints() {\n const permissionsByRoomId = new DefaultMap(\n () => new Signal<Set<Permission>>(new Set())\n );\n\n function update(newHints: Record<string, Permission[]>) {\n batch(() => {\n for (const [roomId, permissions] of Object.entries(newHints)) {\n const signal = permissionsByRoomId.getOrCreate(roomId);\n // Get the existing set of permissions for the room and only ever add permission to this set\n const existingPermissions = new Set(signal.get());\n for (const permission of permissions) {\n existingPermissions.add(permission);\n }\n signal.set(existingPermissions);\n }\n });\n }\n\n function getPermissionForRoomΣ(roomId: string): ISignal<Set<Permission>> {\n return permissionsByRoomId.getOrCreate(roomId);\n }\n\n return {\n getPermissionForRoomΣ,\n\n // Mutations\n update,\n };\n}\n\n/**\n * Notification settings\n *\n * e.g.\n * {\n * email: {\n * thread: true,\n * textMention: false,\n * $customKind: true | false,\n * }\n * slack: {\n * thread: true,\n * textMention: false,\n * $customKind: true | false,\n * }\n * }\n * e.g. {} when before the first successful fetch.\n */\nfunction createStore_forNotificationSettings(\n updates: ISignal<readonly OptimisticUpdate<BaseMetadata, BaseMetadata>[]>\n) {\n const signal = new Signal<NotificationSettings>(\n createNotificationSettings({})\n );\n\n function update(settings: NotificationSettings) {\n signal.set(settings);\n }\n\n return {\n signal: DerivedSignal.from(signal, updates, (base, updates) =>\n applyOptimisticUpdates_forNotificationSettings(base, updates)\n ),\n // Mutations\n update,\n };\n}\n\nfunction createStore_forOptimistic<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: Client<BaseUserMeta, TM, CM>) {\n const signal = new Signal<readonly OptimisticUpdate<TM, CM>[]>([]);\n const syncSource = client[kInternal].createSyncSource();\n\n // Automatically update the global sync status as an effect whenever there\n // are any optimistic updates\n signal.subscribe(() =>\n syncSource.setSyncStatus(\n signal.get().length > 0 ? \"synchronizing\" : \"synchronized\"\n )\n );\n\n function add(\n optimisticUpdate: DistributiveOmit<OptimisticUpdate<TM, CM>, \"id\">\n ): string {\n const id = nanoid();\n const newUpdate: OptimisticUpdate<TM, CM> = { ...optimisticUpdate, id };\n signal.set((state) => [...state, newUpdate]);\n return id;\n }\n\n function remove(optimisticId: string): void {\n signal.set((state) => state.filter((ou) => ou.id !== optimisticId));\n }\n\n return {\n signal: signal.asReadonly(),\n\n // Mutations\n add,\n remove,\n };\n}\n\nexport class UmbrellaStore<TM extends BaseMetadata, CM extends BaseMetadata> {\n #client: Client<BaseUserMeta, TM, CM>;\n\n //\n // Internally, the UmbrellaStore keeps track of a few source signals that can\n // be set and mutated individually. When any of those are mutated then the\n // clean \"external state\" is recomputed.\n //\n // Mutate inputs... ...observe clean/consistent output!\n //\n // .-> Base ThreadDB ---------+ +-------> Clean threads by ID (Part 1)\n // / | |\n // mutate ----> Base Notifications --+ | | +-----> Clean notifications (Part 1)\n // \\ | | | | & notifications by ID\n // | \\ | | Apply | |\n // | `-> OptimisticUpdates --+--+--> Optimistic -+-+-+-+-> Subscriptions (Part 2)\n // \\ | Updates | | |\n // `------- etc etc ---------+ | | +-> History Versions (Part 3)\n // ^ | |\n // | | +---> Room Subscription Settings (Part 4)\n // | |\n // | +-------> Notification Settings (Part 5)\n // |\n // |\n // | ^ ^\n // Signal | |\n // or DerivedSignal DerivedSignals\n // MutableSignal\n //\n\n //\n // Input signals.\n // (Can be mutated directly.)\n //\n // XXX_vincent Now that we have createStore_forX, we should probably also change\n // `threads` to this pattern, ie create a createStore_forThreads helper as\n // well. It almost works like that already anyway!\n readonly threads: ThreadDB<TM, CM>; // Exposes its signal under `.signal` prop\n readonly notifications: ReturnType<typeof createStore_forNotifications>;\n readonly subscriptions: ReturnType<typeof createStore_forSubscriptions>;\n readonly roomSubscriptionSettings: ReturnType<typeof createStore_forRoomSubscriptionSettings>; // prettier-ignore\n readonly historyVersions: ReturnType<typeof createStore_forHistoryVersions>;\n readonly unreadNotificationsCount: ReturnType<\n typeof createStore_forUnreadNotificationsCount\n >;\n readonly urlsMetadata: ReturnType<typeof createStore_forUrlsMetadata>;\n readonly permissionHints: ReturnType<typeof createStore_forPermissionHints>;\n readonly notificationSettings: ReturnType<\n typeof createStore_forNotificationSettings\n >;\n readonly optimisticUpdates: ReturnType<\n typeof createStore_forOptimistic<TM, CM>\n >;\n\n //\n // Output signals.\n // (Readonly, clean, consistent. With optimistic updates applied.)\n //\n // Note that the output of threadifications signal is the same as the ones for\n // threads and notifications separately, but the threadifications signal will\n // be updated whenever either of them change.\n //\n readonly outputs: {\n readonly threadifications: DerivedSignal<CleanThreadifications<TM, CM>>;\n readonly threads: DerivedSignal<ReadonlyThreadDB<TM, CM>>;\n readonly loadingRoomThreads: DefaultMap<\n RoomQueryKey,\n LoadableResource<ThreadsAsyncResult<TM, CM>>\n >;\n readonly loadingUserThreads: DefaultMap<\n UserQueryKey,\n LoadableResource<ThreadsAsyncResult<TM, CM>>\n >;\n readonly notifications: DerivedSignal<CleanNotifications>;\n readonly threadSubscriptions: DerivedSignal<CleanThreadSubscriptions>;\n\n readonly loadingNotifications: DefaultMap<\n InboxNotificationsQueryKey,\n LoadableResource<InboxNotificationsAsyncResult>\n >;\n readonly unreadNotificationsCount: DefaultMap<\n InboxNotificationsQueryKey,\n LoadableResource<UnreadInboxNotificationsCountAsyncResult>\n >;\n readonly roomSubscriptionSettingsByRoomId: DefaultMap<\n RoomId,\n LoadableResource<RoomSubscriptionSettingsAsyncResult>\n >;\n readonly versionsByRoomId: DefaultMap<\n RoomId,\n LoadableResource<HistoryVersionsAsyncResult>\n >;\n readonly notificationSettings: LoadableResource<NotificationSettingsAsyncResult>;\n readonly aiChats: DefaultMap<\n AiChatsQueryKey,\n LoadableResource<AiChatsAsyncResult>\n >;\n readonly messagesByChatId: DefaultMap<\n string,\n DefaultMap<MessageId | null, LoadableResource<AiChatMessagesAsyncResult>>\n >;\n readonly aiChatById: DefaultMap<\n string,\n LoadableResource<AiChatAsyncResult>\n >;\n readonly urlMetadataByUrl: DefaultMap<\n string,\n LoadableResource<UrlMetadataAsyncResult>\n >;\n };\n\n // Notifications\n #notificationsLastRequestedAt: Date | null = null; // Keeps track of when we successfully requested an inbox notifications update for the last time. Will be `null` as long as the first successful fetch hasn't happened yet.\n\n // Room Threads\n #roomThreadsLastRequestedAtByRoom = new Map<RoomId, Date>();\n\n // User Threads\n #userThreadsLastRequestedAt: Date | null = null;\n\n // Room versions\n #roomVersionsLastRequestedAtByRoom = new Map<RoomId, Date>();\n\n // Notification Settings\n #notificationSettings: SinglePageResource;\n\n constructor(client: OpaqueClient) {\n this.#client = client[kInternal].as<TM, CM>();\n\n this.optimisticUpdates = createStore_forOptimistic<TM, CM>(this.#client);\n this.permissionHints = createStore_forPermissionHints();\n\n const notificationSettingsFetcher = async (): Promise<void> => {\n const result = await this.#client.getNotificationSettings();\n this.notificationSettings.update(result);\n };\n\n this.notificationSettings = createStore_forNotificationSettings(\n this.optimisticUpdates.signal\n );\n\n this.#notificationSettings = new SinglePageResource(\n notificationSettingsFetcher\n );\n\n this.threads = new ThreadDB();\n\n this.subscriptions = createStore_forSubscriptions(\n this.optimisticUpdates.signal,\n this.threads\n );\n\n this.notifications = createStore_forNotifications();\n this.roomSubscriptionSettings = createStore_forRoomSubscriptionSettings(\n this.optimisticUpdates.signal\n );\n this.historyVersions = createStore_forHistoryVersions();\n this.unreadNotificationsCount = createStore_forUnreadNotificationsCount();\n this.urlsMetadata = createStore_forUrlsMetadata();\n\n const threadifications = DerivedSignal.from(\n this.threads.signal,\n this.notifications.signal,\n this.optimisticUpdates.signal,\n (ts, ns, updates) =>\n applyOptimisticUpdates_forThreadifications(ts, ns, updates)\n );\n\n const threads = DerivedSignal.from(threadifications, (s) => s.threadsDB);\n\n const notifications = DerivedSignal.from(\n threadifications,\n (s) => ({\n sortedNotifications: s.sortedNotifications,\n notificationsById: s.notificationsById,\n }),\n shallow\n );\n\n const threadSubscriptions = DerivedSignal.from(\n notifications,\n this.subscriptions.signal,\n (n, s) => ({\n subscriptions: s,\n notifications: n.sortedNotifications,\n })\n );\n\n const loadingUserThreads = new DefaultMap(\n (\n queryKey: UserQueryKey\n ): LoadableResource<ThreadsAsyncResult<TM, CM>> => {\n const query = JSON.parse(queryKey) as ThreadsQuery<TM>;\n\n const resource = new PaginatedResource(async (cursor?: string) => {\n const result = await this.#client[\n kInternal\n ].httpClient.getUserThreads_experimental({\n cursor,\n query,\n });\n this.updateThreadifications(\n result.threads,\n result.inboxNotifications,\n result.subscriptions\n );\n\n this.permissionHints.update(result.permissionHints);\n\n // We initialize the `_userThreadsLastRequestedAt` date using the server timestamp after we've loaded the first page of inbox notifications.\n if (this.#userThreadsLastRequestedAt === null) {\n this.#userThreadsLastRequestedAt = result.requestedAt;\n }\n\n return result.nextCursor;\n });\n\n const signal = DerivedSignal.from((): ThreadsAsyncResult<TM, CM> => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n const subscriptions = threadSubscriptions.get().subscriptions;\n\n const threads = this.outputs.threads.get().findMany(\n undefined, // Do _not_ filter by roomId\n query ?? {},\n \"desc\",\n subscriptions\n );\n\n const page = result.data;\n return {\n isLoading: false,\n threads,\n hasFetchedAll: page.hasFetchedAll,\n isFetchingMore: page.isFetchingMore,\n fetchMoreError: page.fetchMoreError,\n fetchMore: page.fetchMore,\n };\n }, shallow2);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n }\n );\n\n const loadingRoomThreads = new DefaultMap(\n (\n queryKey: RoomQueryKey\n ): LoadableResource<ThreadsAsyncResult<TM, CM>> => {\n const [roomId, query] = JSON.parse(queryKey) as [\n roomId: RoomId,\n query: ThreadsQuery<TM>,\n ];\n\n const resource = new PaginatedResource(async (cursor?: string) => {\n const result = await this.#client[kInternal].httpClient.getThreads({\n roomId,\n cursor,\n query,\n });\n this.updateThreadifications(\n result.threads,\n result.inboxNotifications,\n result.subscriptions\n );\n\n this.permissionHints.update(result.permissionHints);\n\n const lastRequestedAt =\n this.#roomThreadsLastRequestedAtByRoom.get(roomId);\n\n /**\n * We set the `lastRequestedAt` value for the room to the timestamp returned by the current request if:\n * 1. The `lastRequestedAt` value for the room has not been set\n * OR\n * 2. The `lastRequestedAt` value for the room is older than the timestamp returned by the current request\n */\n if (\n lastRequestedAt === undefined ||\n lastRequestedAt > result.requestedAt\n ) {\n this.#roomThreadsLastRequestedAtByRoom.set(\n roomId,\n result.requestedAt\n );\n }\n\n return result.nextCursor;\n });\n\n const signal = DerivedSignal.from((): ThreadsAsyncResult<TM, CM> => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n const subscriptions = threadSubscriptions.get().subscriptions;\n\n const threads = this.outputs.threads\n .get()\n .findMany(roomId, query ?? {}, \"asc\", subscriptions);\n\n const page = result.data;\n return {\n isLoading: false,\n threads,\n hasFetchedAll: page.hasFetchedAll,\n isFetchingMore: page.isFetchingMore,\n fetchMoreError: page.fetchMoreError,\n fetchMore: page.fetchMore,\n };\n }, shallow2);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n }\n );\n\n const loadingNotifications = new DefaultMap(\n (\n queryKey: InboxNotificationsQueryKey\n ): LoadableResource<InboxNotificationsAsyncResult> => {\n const query = JSON.parse(queryKey) as InboxNotificationsQuery;\n\n const resource = new PaginatedResource(async (cursor?: string) => {\n const result = await this.#client.getInboxNotifications({\n cursor,\n query,\n });\n\n this.updateThreadifications(\n result.threads,\n result.inboxNotifications,\n result.subscriptions\n );\n\n // We initialize the `_lastRequestedNotificationsAt` date using the server timestamp after we've loaded the first page of inbox notifications.\n if (this.#notificationsLastRequestedAt === null) {\n this.#notificationsLastRequestedAt = result.requestedAt;\n }\n\n const nextCursor = result.nextCursor;\n return nextCursor;\n });\n\n const signal = DerivedSignal.from((): InboxNotificationsAsyncResult => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n const crit: ((\n inboxNotification: InboxNotificationData\n ) => boolean)[] = [];\n\n if (query !== undefined) {\n crit.push(makeInboxNotificationsFilter(query));\n }\n const inboxNotifications = this.outputs.notifications\n .get()\n .sortedNotifications.filter((inboxNotification) =>\n crit.every((pred) => pred(inboxNotification))\n );\n\n const page = result.data;\n return {\n isLoading: false,\n inboxNotifications,\n hasFetchedAll: page.hasFetchedAll,\n isFetchingMore: page.isFetchingMore,\n fetchMoreError: page.fetchMoreError,\n fetchMore: page.fetchMore,\n };\n }, shallow2);\n\n return {\n signal,\n waitUntilLoaded: resource.waitUntilLoaded,\n };\n }\n );\n\n const unreadNotificationsCount = new DefaultMap(\n (\n queryKey: InboxNotificationsQueryKey\n ): LoadableResource<UnreadInboxNotificationsCountAsyncResult> => {\n const query = JSON.parse(queryKey) as InboxNotificationsQuery;\n\n const resource = new SinglePageResource(async () => {\n const result = await this.#client.getUnreadInboxNotificationsCount({\n query,\n });\n\n this.unreadNotificationsCount.update(queryKey, result);\n });\n\n const signal = DerivedSignal.from(\n (): UnreadInboxNotificationsCountAsyncResult => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n } else {\n return ASYNC_OK(\n \"count\",\n nn(this.unreadNotificationsCount.signal.get()[queryKey])\n );\n }\n },\n shallow\n );\n\n return {\n signal,\n waitUntilLoaded: resource.waitUntilLoaded,\n };\n }\n );\n\n const roomSubscriptionSettingsByRoomId = new DefaultMap(\n (roomId: RoomId) => {\n const resource = new SinglePageResource(async () => {\n const room = this.#client.getRoom(roomId);\n if (room === null) {\n throw new Error(`Room '${roomId}' is not available on client`);\n }\n\n const result = await room.getSubscriptionSettings();\n this.roomSubscriptionSettings.update(roomId, result);\n });\n\n const signal = DerivedSignal.from(() => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n } else {\n return ASYNC_OK(\n \"settings\",\n nn(this.roomSubscriptionSettings.signal.get()[roomId])\n );\n }\n }, shallow);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n }\n );\n\n const versionsByRoomId = new DefaultMap(\n (roomId: RoomId): LoadableResource<HistoryVersionsAsyncResult> => {\n const resource = new SinglePageResource(async () => {\n const room = this.#client.getRoom(roomId);\n if (room === null) {\n throw new Error(`Room '${roomId}' is not available on client`);\n }\n\n const result = await room[kInternal].listTextVersions();\n this.historyVersions.update(roomId, result.versions);\n\n const lastRequestedAt =\n this.#roomVersionsLastRequestedAtByRoom.get(roomId);\n\n if (\n lastRequestedAt === undefined ||\n lastRequestedAt > result.requestedAt\n ) {\n this.#roomVersionsLastRequestedAtByRoom.set(\n roomId,\n result.requestedAt\n );\n }\n });\n\n const signal = DerivedSignal.from((): HistoryVersionsAsyncResult => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n } else {\n return ASYNC_OK(\n \"versions\",\n Object.values(this.historyVersions.signal.get()[roomId] ?? {})\n );\n }\n }, shallow);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n }\n );\n\n const notificationSettings: LoadableResource<NotificationSettingsAsyncResult> =\n {\n signal: DerivedSignal.from((): NotificationSettingsAsyncResult => {\n const result = this.#notificationSettings.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n return ASYNC_OK(\n \"settings\",\n nn(this.notificationSettings.signal.get())\n );\n }, shallow),\n waitUntilLoaded: this.#notificationSettings.waitUntilLoaded,\n };\n\n const aiChats = new DefaultMap(\n (queryKey: AiChatsQueryKey): LoadableResource<AiChatsAsyncResult> => {\n const query = JSON.parse(queryKey) as AiChatsQuery;\n const resource = new PaginatedResource(async (cursor?: string) => {\n const result = await this.#client[kInternal].ai.getChats({\n cursor: cursor as Cursor,\n query,\n });\n return result.nextCursor;\n });\n\n const signal = DerivedSignal.from((): AiChatsAsyncResult => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n const chats = this.#client[kInternal].ai.queryChats(query);\n\n return {\n isLoading: false,\n chats,\n hasFetchedAll: result.data.hasFetchedAll,\n isFetchingMore: result.data.isFetchingMore,\n fetchMore: result.data.fetchMore,\n fetchMoreError: result.data.fetchMoreError,\n };\n }, shallow);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n }\n );\n\n const messagesByChatId = new DefaultMap((chatId: string) => {\n const resourceΣ = new SinglePageResource(async () => {\n await this.#client[kInternal].ai.getMessageTree(chatId);\n });\n\n return new DefaultMap(\n (\n branch: MessageId | null\n ): LoadableResource<AiChatMessagesAsyncResult> => {\n const signal = DerivedSignal.from((): AiChatMessagesAsyncResult => {\n const result = resourceΣ.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n return ASYNC_OK(\n \"messages\",\n this.#client[kInternal].ai.signals\n .getChatMessagesForBranchΣ(chatId, branch ?? undefined)\n .get()\n );\n });\n\n return { signal, waitUntilLoaded: resourceΣ.waitUntilLoaded };\n }\n );\n });\n\n const aiChatById = new DefaultMap((chatId: string) => {\n const resource = new SinglePageResource(async () => {\n await this.#client[kInternal].ai.getOrCreateChat(chatId);\n });\n\n const signal = DerivedSignal.from(() => {\n const chat = this.#client[kInternal].ai.getChatById(chatId);\n if (chat === undefined) {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n } else {\n return ASYNC_OK(\n \"chat\",\n nn(this.#client[kInternal].ai.getChatById(chatId))\n );\n }\n } else {\n return ASYNC_OK(\n \"chat\",\n nn(this.#client[kInternal].ai.getChatById(chatId))\n );\n }\n }, shallow);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n });\n\n const urlMetadataByUrl = new DefaultMap(\n (url: string): LoadableResource<UrlMetadataAsyncResult> => {\n const resource = new SinglePageResource(async () => {\n const metadata =\n await this.#client[kInternal].httpClient.getUrlMetadata(url);\n this.urlsMetadata.update(url, metadata);\n }, false);\n\n const signal = DerivedSignal.from((): UrlMetadataAsyncResult => {\n const result = resource.get();\n if (result.isLoading || result.error) {\n return result;\n }\n\n return ASYNC_OK(\"metadata\", nn(this.urlsMetadata.signal.get()[url]));\n }, shallow);\n\n return { signal, waitUntilLoaded: resource.waitUntilLoaded };\n }\n );\n\n this.outputs = {\n threadifications,\n threads,\n loadingRoomThreads,\n loadingUserThreads,\n notifications,\n loadingNotifications,\n unreadNotificationsCount,\n roomSubscriptionSettingsByRoomId,\n versionsByRoomId,\n notificationSettings,\n threadSubscriptions,\n aiChats,\n messagesByChatId,\n aiChatById,\n urlMetadataByUrl,\n };\n\n // Auto-bind all of this class' methods here, so we can use stable\n // references to them (most important for use in useSyncExternalStore)\n autobind(this);\n }\n\n /**\n * Updates an existing inbox notification with a new value, replacing the\n * corresponding optimistic update.\n *\n * This will not update anything if the inbox notification ID isn't found.\n */\n public markInboxNotificationRead(\n inboxNotificationId: string,\n readAt: Date,\n optimisticId: string\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.notifications.markRead(inboxNotificationId, readAt);\n });\n }\n\n public markAllInboxNotificationsRead(\n optimisticId: string,\n readAt: Date\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.notifications.markAllRead(readAt);\n });\n }\n\n /**\n * Deletes an existing inbox notification, replacing the corresponding\n * optimistic update.\n */\n public deleteInboxNotification(\n inboxNotificationId: string,\n optimisticId: string\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.notifications.delete(inboxNotificationId);\n });\n }\n\n /**\n * Deletes *all* inbox notifications, replacing the corresponding optimistic\n * update.\n */\n public deleteAllInboxNotifications(optimisticId: string): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.notifications.clear();\n });\n }\n\n /**\n * Creates an existing subscription, replacing the corresponding\n * optimistic update.\n */\n public createSubscription(\n subscription: SubscriptionData,\n optimisticId: string\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.subscriptions.create(subscription);\n });\n }\n\n /**\n * Deletes an existing subscription, replacing the corresponding\n * optimistic update.\n */\n public deleteSubscription(\n subscriptionKey: SubscriptionKey,\n optimisticId: string\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.subscriptions.delete(subscriptionKey);\n });\n }\n\n /**\n * Creates an new thread, replacing the corresponding optimistic update.\n */\n public createThread(\n optimisticId: string,\n thread: Readonly<ThreadDataWithDeleteInfo<TM, CM>>\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.threads.upsert(thread);\n });\n }\n\n /**\n * Updates an existing thread with a new value, replacing the corresponding\n * optimistic update.\n *\n * This will not update anything if:\n * - The thread ID isn't found; or\n * - The thread ID was already deleted; or\n * - The thread ID was updated more recently than the optimistic update's\n * timestamp (if given)\n */\n #updateThread(\n threadId: string,\n optimisticId: string | null,\n callback: (\n thread: Readonly<ThreadDataWithDeleteInfo<TM, CM>>\n ) => Readonly<ThreadDataWithDeleteInfo<TM, CM>>,\n updatedAt?: Date // TODO We could look this up from the optimisticUpdate instead?\n ): void {\n batch(() => {\n if (optimisticId !== null) {\n this.optimisticUpdates.remove(optimisticId);\n }\n\n const db = this.threads;\n const existing = db.get(threadId);\n if (!existing) return;\n if (!!updatedAt && existing.updatedAt > updatedAt) return;\n db.upsert(callback(existing));\n });\n }\n\n public patchThread(\n threadId: string,\n optimisticId: string | null,\n patch: {\n // Only these fields are currently supported to patch\n metadata?: TM;\n resolved?: boolean;\n },\n updatedAt: Date // TODO We could look this up from the optimisticUpdate instead?\n ): void {\n return this.#updateThread(\n threadId,\n optimisticId,\n (thread) => ({ ...thread, ...compactObject(patch) }),\n updatedAt\n );\n }\n\n public addReaction(\n threadId: string,\n optimisticId: string | null,\n commentId: string,\n reaction: CommentUserReaction,\n createdAt: Date // TODO We could look this up from the optimisticUpdate instead?\n ): void {\n this.#updateThread(\n threadId,\n optimisticId,\n (thread) => applyAddReaction(thread, commentId, reaction),\n createdAt\n );\n }\n\n public removeReaction(\n threadId: string,\n optimisticId: string | null,\n commentId: string,\n emoji: string,\n userId: string,\n removedAt: Date\n ): void {\n this.#updateThread(\n threadId,\n optimisticId,\n (thread) =>\n applyRemoveReaction(thread, commentId, emoji, userId, removedAt),\n removedAt\n );\n }\n\n /**\n * Soft-deletes an existing thread by setting its `deletedAt` value,\n * replacing the corresponding optimistic update.\n *\n * This will not update anything if:\n * - The thread ID isn't found; or\n * - The thread ID was already deleted\n */\n public deleteThread(threadId: string, optimisticId: string | null): void {\n return this.#updateThread(\n threadId,\n optimisticId,\n\n // A deletion is actually an update of the deletedAt property internally\n (thread) => ({ ...thread, updatedAt: new Date(), deletedAt: new Date() })\n );\n }\n\n /**\n * Creates an existing comment and ensures the associated notification is\n * updated correctly, replacing the corresponding optimistic update.\n */\n public createComment(\n newComment: CommentData<CM>,\n optimisticId: string\n ): void {\n // Batch 1️⃣ + 2️⃣ + 3️⃣\n batch(() => {\n // 1️⃣\n this.optimisticUpdates.remove(optimisticId);\n\n // If the associated thread is not found, we cannot create a comment under it\n const existingThread = this.threads.get(newComment.threadId);\n if (!existingThread) {\n return;\n }\n\n // 2️⃣ Update the thread instance by adding a comment under it\n this.threads.upsert(applyUpsertComment(existingThread, newComment));\n\n // 3️⃣ Update the associated inbox notification (if any)\n this.notifications.updateAssociatedNotification(newComment);\n });\n }\n\n public editComment(\n threadId: string,\n optimisticId: string,\n editedComment: CommentData<CM>\n ): void {\n return this.#updateThread(threadId, optimisticId, (thread) =>\n applyUpsertComment(thread, editedComment)\n );\n }\n\n public editCommentMetadata(\n threadId: string,\n commentId: string,\n optimisticId: string,\n updatedMetadata: CM,\n updatedAt: Date\n ): void {\n return this.#updateThread(\n threadId,\n optimisticId,\n (thread) => {\n const comment = thread.comments.find((c) => c.id === commentId);\n if (comment === undefined) {\n return thread;\n }\n return {\n ...thread,\n updatedAt,\n comments: thread.comments.map((c) =>\n c.id === commentId ? { ...c, metadata: updatedMetadata } : c\n ),\n };\n },\n updatedAt\n );\n }\n\n public deleteComment(\n threadId: string,\n optimisticId: string,\n commentId: string,\n deletedAt: Date\n ): void {\n return this.#updateThread(\n threadId,\n optimisticId,\n (thread) => applyDeleteComment(thread, commentId, deletedAt),\n deletedAt\n );\n }\n\n public updateThreadifications(\n threads: ThreadData<TM, CM>[],\n notifications: InboxNotificationData[],\n subscriptions: SubscriptionData[],\n deletedThreads: ThreadDeleteInfo[] = [],\n deletedNotifications: InboxNotificationDeleteInfo[] = [],\n deletedSubscriptions: SubscriptionDeleteInfo[] = []\n ): void {\n batch(() => {\n this.threads.applyDelta(threads, deletedThreads);\n this.notifications.applyDelta(notifications, deletedNotifications);\n this.subscriptions.applyDelta(subscriptions, deletedSubscriptions);\n });\n }\n\n /**\n * Updates existing subscription settings for a room with a new value,\n * replacing the corresponding optimistic update.\n */\n public updateRoomSubscriptionSettings(\n roomId: string,\n optimisticId: string,\n settings: Readonly<RoomSubscriptionSettings>\n ): void {\n batch(() => {\n this.optimisticUpdates.remove(optimisticId);\n this.roomSubscriptionSettings.update(roomId, settings);\n });\n }\n\n public async fetchNotificationsDeltaUpdate(signal: AbortSignal) {\n const lastRequestedAt = this.#notificationsLastRequestedAt;\n if (lastRequestedAt === null) {\n return;\n }\n\n const result = await this.#client.getInboxNotificationsSince({\n since: lastRequestedAt,\n signal,\n });\n\n if (lastRequestedAt < result.requestedAt) {\n this.#notificationsLastRequestedAt = result.requestedAt;\n }\n\n this.updateThreadifications(\n result.threads.updated,\n result.inboxNotifications.updated,\n result.subscriptions.updated,\n result.threads.deleted,\n result.inboxNotifications.deleted,\n result.subscriptions.deleted\n );\n }\n\n public async fetchUnreadNotificationsCount(\n queryKey: InboxNotificationsQueryKey,\n signal: AbortSignal\n ) {\n const query = JSON.parse(queryKey) as InboxNotificationsQuery;\n\n const result = await this.#client.getUnreadInboxNotificationsCount({\n query,\n signal,\n });\n\n this.unreadNotificationsCount.update(queryKey, result);\n }\n\n public async fetchRoomThreadsDeltaUpdate(\n roomId: string,\n signal: AbortSignal\n ) {\n const lastRequestedAt = this.#roomThreadsLastRequestedAtByRoom.get(roomId);\n if (lastRequestedAt === undefined) {\n return;\n }\n\n const updates = await this.#client[kInternal].httpClient.getThreadsSince({\n roomId,\n since: lastRequestedAt,\n signal,\n });\n\n this.updateThreadifications(\n updates.threads.updated,\n updates.inboxNotifications.updated,\n updates.subscriptions.updated,\n updates.threads.deleted,\n updates.inboxNotifications.deleted,\n updates.subscriptions.deleted\n );\n\n this.permissionHints.update(updates.permissionHints);\n\n if (lastRequestedAt < updates.requestedAt) {\n // Update the `lastRequestedAt` value for the room to the timestamp returned by the current request\n this.#roomThreadsLastRequestedAtByRoom.set(roomId, updates.requestedAt);\n }\n }\n\n public async fetchUserThreadsDeltaUpdate(signal: AbortSignal) {\n const lastRequestedAt = this.#userThreadsLastRequestedAt;\n if (lastRequestedAt === null) {\n return;\n }\n\n const result = await this.#client[\n kInternal\n ].httpClient.getUserThreadsSince_experimental({\n since: lastRequestedAt,\n signal,\n });\n\n if (lastRequestedAt < result.requestedAt) {\n this.#notificationsLastRequestedAt = result.requestedAt;\n }\n\n this.updateThreadifications(\n result.threads.updated,\n result.inboxNotifications.updated,\n result.subscriptions.updated,\n result.threads.deleted,\n result.inboxNotifications.deleted,\n result.subscriptions.deleted\n );\n\n this.permissionHints.update(result.permissionHints);\n }\n\n public async fetchRoomVersionsDeltaUpdate(\n roomId: string,\n signal: AbortSignal\n ) {\n const lastRequestedAt = this.#roomVersionsLastRequestedAtByRoom.get(roomId);\n if (lastRequestedAt === undefined) {\n return;\n }\n\n const room = nn(\n this.#client.getRoom(roomId),\n `Room with id ${roomId} is not available on client`\n );\n\n const updates = await room[kInternal].listTextVersionsSince({\n since: lastRequestedAt,\n signal,\n });\n\n this.historyVersions.update(roomId, updates.versions);\n\n if (lastRequestedAt < updates.requestedAt) {\n // Update the `lastRequestedAt` value for the room to the timestamp returned by the current request\n this.#roomVersionsLastRequestedAtByRoom.set(roomId, updates.requestedAt);\n }\n }\n\n public async refreshRoomSubscriptionSettings(\n roomId: string,\n signal: AbortSignal\n ) {\n const room = nn(\n this.#client.getRoom(roomId),\n `Room with id ${roomId} is not available on client`\n );\n const result = await room.getSubscriptionSettings({ signal });\n this.roomSubscriptionSettings.update(roomId, result);\n }\n\n /**\n * Refresh notification settings from poller\n */\n public async refreshNotificationSettings(signal: AbortSignal) {\n const result = await this.#client.getNotificationSettings({\n signal,\n });\n this.notificationSettings.update(result);\n }\n\n /**\n * Updates notification settings with a new value, replacing the\n * corresponding optimistic update.\n */\n public updateNotificationSettings_confirmOptimisticUpdate(\n settings: NotificationSettings,\n optimisticUpdateId: string\n ): void {\n // Batch 1️⃣ + 2️⃣\n batch(() => {\n this.optimisticUpdates.remove(optimisticUpdateId); // 1️⃣\n this.notificationSettings.update(settings); // 2️⃣\n });\n }\n}\n\n/**\n * Applies optimistic updates, removes deleted threads, sorts results in\n * a stable way, removes internal fields that should not be exposed publicly.\n */\nfunction applyOptimisticUpdates_forThreadifications<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n baseThreadsDB: ThreadDB<TM, CM>,\n notificationsLUT: NotificationsLUT,\n optimisticUpdates: readonly OptimisticUpdate<TM, CM>[]\n): CleanThreadifications<TM, CM> {\n const threadsDB = baseThreadsDB.clone();\n let notificationsById = Object.fromEntries(notificationsLUT);\n\n for (const optimisticUpdate of optimisticUpdates) {\n switch (optimisticUpdate.type) {\n case \"create-thread\": {\n threadsDB.upsert(optimisticUpdate.thread);\n break;\n }\n\n case \"edit-thread-metadata\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n // If the thread has been updated since the optimistic update, we do not apply the update\n if (thread.updatedAt > optimisticUpdate.updatedAt) {\n break;\n }\n\n threadsDB.upsert({\n ...thread,\n updatedAt: optimisticUpdate.updatedAt,\n metadata: {\n ...thread.metadata,\n ...optimisticUpdate.metadata,\n },\n });\n break;\n }\n\n case \"mark-thread-as-resolved\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert({ ...thread, resolved: true });\n break;\n }\n\n case \"mark-thread-as-unresolved\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert({ ...thread, resolved: false });\n break;\n }\n\n case \"create-comment\": {\n const thread = threadsDB.get(optimisticUpdate.comment.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert(applyUpsertComment(thread, optimisticUpdate.comment));\n\n const inboxNotification = Object.values(notificationsById).find(\n (notification) =>\n notification.kind === \"thread\" &&\n notification.threadId === thread.id\n );\n\n if (inboxNotification === undefined) {\n break;\n }\n\n notificationsById[inboxNotification.id] = {\n ...inboxNotification,\n notifiedAt: optimisticUpdate.comment.createdAt,\n readAt: optimisticUpdate.comment.createdAt,\n };\n\n break;\n }\n\n case \"edit-comment\": {\n const thread = threadsDB.get(optimisticUpdate.comment.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert(applyUpsertComment(thread, optimisticUpdate.comment));\n break;\n }\n\n case \"edit-comment-metadata\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n // If the thread has been updated since the optimistic update, we do not apply the update\n if (thread.updatedAt > optimisticUpdate.updatedAt) {\n break;\n }\n\n const existingComment = thread.comments.find(\n (c) => c.id === optimisticUpdate.commentId\n );\n if (existingComment === undefined) break;\n\n threadsDB.upsert(\n applyUpsertComment(thread, {\n ...existingComment,\n metadata: {\n ...existingComment.metadata,\n ...optimisticUpdate.metadata,\n },\n })\n );\n break;\n }\n\n case \"delete-comment\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert(\n applyDeleteComment(\n thread,\n optimisticUpdate.commentId,\n optimisticUpdate.deletedAt\n )\n );\n break;\n }\n\n case \"delete-thread\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert({\n ...thread,\n deletedAt: optimisticUpdate.deletedAt,\n updatedAt: optimisticUpdate.deletedAt,\n comments: [],\n });\n break;\n }\n\n case \"add-reaction\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert(\n applyAddReaction(\n thread,\n optimisticUpdate.commentId,\n optimisticUpdate.reaction\n )\n );\n break;\n }\n\n case \"remove-reaction\": {\n const thread = threadsDB.get(optimisticUpdate.threadId);\n if (thread === undefined) break;\n\n threadsDB.upsert(\n applyRemoveReaction(\n thread,\n optimisticUpdate.commentId,\n optimisticUpdate.emoji,\n optimisticUpdate.userId,\n optimisticUpdate.removedAt\n )\n );\n break;\n }\n\n case \"mark-inbox-notification-as-read\": {\n const ibn = notificationsById[optimisticUpdate.inboxNotificationId];\n\n // If the inbox notification doesn't exist, we do not apply the update\n if (ibn === undefined) {\n break;\n }\n\n notificationsById[optimisticUpdate.inboxNotificationId] = {\n ...ibn,\n readAt: optimisticUpdate.readAt,\n };\n break;\n }\n case \"mark-all-inbox-notifications-as-read\": {\n for (const id in notificationsById) {\n const ibn = notificationsById[id];\n\n // If the inbox notification doesn't exist, we do not apply the update\n if (ibn === undefined) {\n break;\n }\n\n notificationsById[id] = {\n ...ibn,\n readAt: optimisticUpdate.readAt,\n };\n }\n break;\n }\n case \"delete-inbox-notification\": {\n delete notificationsById[optimisticUpdate.inboxNotificationId];\n break;\n }\n case \"delete-all-inbox-notifications\": {\n notificationsById = {};\n break;\n }\n }\n }\n\n // TODO Maybe consider also removing these from the inboxNotificationsById registry?\n const sortedNotifications =\n // Sort so that the most recent notifications are first\n Object.values(notificationsById)\n .filter((ibn) =>\n ibn.kind === \"thread\" ? threadsDB.get(ibn.threadId) !== undefined : true\n )\n .sort((a, b) => b.notifiedAt.getTime() - a.notifiedAt.getTime());\n\n return {\n sortedNotifications,\n notificationsById,\n threadsDB,\n };\n}\n\n/**\n * Applies optimistic updates to room subscription settings in a stable way.\n */\nfunction applyOptimisticUpdates_forRoomSubscriptionSettings(\n settingsLUT: RoomSubscriptionSettingsLUT,\n optimisticUpdates: readonly OptimisticUpdate<BaseMetadata, BaseMetadata>[]\n): RoomSubscriptionSettingsByRoomId {\n const roomSubscriptionSettingsByRoomId = Object.fromEntries(settingsLUT);\n\n for (const optimisticUpdate of optimisticUpdates) {\n switch (optimisticUpdate.type) {\n case \"update-room-subscription-settings\": {\n const settings =\n roomSubscriptionSettingsByRoomId[optimisticUpdate.roomId];\n\n // If the settings don't exist, we do not apply the update\n if (settings === undefined) {\n break;\n }\n\n roomSubscriptionSettingsByRoomId[optimisticUpdate.roomId] = {\n ...settings,\n ...optimisticUpdate.settings,\n };\n }\n }\n }\n return roomSubscriptionSettingsByRoomId;\n}\n\n/**\n * Applies optimistic updates to subscriptions in a stable way.\n */\nfunction applyOptimisticUpdates_forSubscriptions(\n subscriptionsLUT: SubscriptionsLUT,\n threads: ReadonlyThreadDB<BaseMetadata, BaseMetadata>,\n optimisticUpdates: readonly OptimisticUpdate<BaseMetadata, BaseMetadata>[]\n): SubscriptionsByKey {\n const subscriptions = Object.fromEntries(subscriptionsLUT);\n\n for (const update of optimisticUpdates) {\n switch (update.type) {\n case \"update-room-subscription-settings\": {\n // Other room subscription settings don't affect optimistic updates at the moment\n if (!update.settings.threads) {\n continue;\n }\n\n const roomThreads = threads.findMany(\n update.roomId,\n undefined,\n \"desc\",\n undefined\n );\n\n for (const thread of roomThreads) {\n const subscriptionKey = getSubscriptionKey(\"thread\", thread.id);\n\n switch (update.settings.threads) {\n // Create subscriptions for all existing threads in the room\n case \"all\": {\n subscriptions[subscriptionKey] = {\n kind: \"thread\",\n subjectId: thread.id,\n createdAt: new Date(),\n };\n break;\n }\n\n // Delete subscriptions for all existing threads in the room\n case \"none\": {\n delete subscriptions[subscriptionKey];\n break;\n }\n\n case \"replies_and_mentions\": {\n // TODO: We can't go through the comments and create subscriptions optimistically because\n // we might not have group members for all group IDs which means we can't reliably\n // know if the user was mentioned with a group mention.\n break;\n }\n\n default:\n assertNever(\n update.settings.threads,\n \"Unexpected thread subscription settings.\"\n );\n }\n }\n }\n\n // TODO: We can't do the following pseudo-code yet because we don't have the room subscription settings\n // in the umbrella store when `useRoomSubscriptionSettings` isn't used.\n //\n // case \"create-thread\":\n // case \"create-comment\":\n // // Create a subscription (if it doesn't exist yet) for the thread optimistically, unless the `\"thread\"`\n // // room subscription settings for the user and the thread's room are set to `\"none\"`.\n }\n }\n\n return subscriptions;\n}\n\n/**\n * Applies optimistic update to notification settings in a stable way.\n * It's a deep update, and remove potential `undefined` properties from the final\n * output object because we update with a deep partial of `NotificationSettings`.\n *\n * Exported for unit tests only.\n */\nexport function applyOptimisticUpdates_forNotificationSettings(\n settings: NotificationSettings,\n optimisticUpdates: readonly OptimisticUpdate<BaseMetadata, BaseMetadata>[]\n): NotificationSettings {\n let outcoming: NotificationSettings = settings;\n\n for (const update of optimisticUpdates) {\n if (update.type === \"update-notification-settings\") {\n outcoming = patchNotificationSettings(outcoming, update.settings);\n }\n }\n\n return outcoming;\n}\n\n/**\n * Compares two inbox notifications to determine which one is newer.\n * @param inboxNotificationA The first inbox notification to compare.\n * @param inboxNotificationB The second inbox notification to compare.\n * @returns 1 if inboxNotificationA is newer, -1 if inboxNotificationB is newer, or 0 if they are the same age or can't be compared.\n */\nexport function compareInboxNotifications(\n inboxNotificationA: InboxNotificationData,\n inboxNotificationB: InboxNotificationData\n): number {\n if (inboxNotificationA.notifiedAt > inboxNotificationB.notifiedAt) {\n return 1;\n } else if (inboxNotificationA.notifiedAt < inboxNotificationB.notifiedAt) {\n return -1;\n }\n\n // notifiedAt times are the same, compare readAt times if both are not null\n if (inboxNotificationA.readAt && inboxNotificationB.readAt) {\n return inboxNotificationA.readAt > inboxNotificationB.readAt\n ? 1\n : inboxNotificationA.readAt < inboxNotificationB.readAt\n ? -1\n : 0;\n } else if (inboxNotificationA.readAt || inboxNotificationB.readAt) {\n return inboxNotificationA.readAt ? 1 : -1;\n }\n\n // If all dates are equal, return 0\n return 0;\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyUpsertComment<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n thread: ThreadDataWithDeleteInfo<TM, CM>,\n comment: CommentData<CM>\n): ThreadDataWithDeleteInfo<TM, CM> {\n // If the thread has been deleted, we do not apply the update\n if (thread.deletedAt !== undefined) {\n // Note: only the unit tests are passing in deleted threads here. In all\n // production code, this is never invoked for deleted threads.\n return thread;\n }\n\n // Validate that the comment belongs to the thread\n if (comment.threadId !== thread.id) {\n console.warn(\n `Comment ${comment.id} does not belong to thread ${thread.id}`\n );\n return thread;\n }\n\n const existingComment = thread.comments.find(\n (existingComment) => existingComment.id === comment.id\n );\n\n // If the comment doesn't exist in the thread, add the comment\n if (existingComment === undefined) {\n const updatedAt = new Date(\n Math.max(thread.updatedAt.getTime(), comment.createdAt.getTime())\n );\n\n const updatedThread = {\n ...thread,\n updatedAt,\n comments: [...thread.comments, comment],\n };\n\n return updatedThread;\n }\n\n // If the comment exists in the thread and has been deleted, only update its metadata\n if (existingComment.deletedAt !== undefined) {\n const updatedComment = {\n ...existingComment,\n metadata: {\n ...existingComment.metadata,\n ...comment.metadata,\n },\n };\n\n const updatedComments = thread.comments.map((c) =>\n c.id === comment.id ? updatedComment : c\n );\n\n return {\n ...thread,\n comments: updatedComments,\n };\n }\n\n // Proceed to update the comment if:\n // 1. The existing comment has not been edited\n // 2. The incoming comment has not been edited (i.e. it's a new comment)\n // 3. The incoming comment has been edited more recently than the existing comment\n if (\n existingComment.editedAt === undefined ||\n comment.editedAt === undefined ||\n existingComment.editedAt <= comment.editedAt\n ) {\n const updatedComments = thread.comments.map((existingComment) =>\n existingComment.id === comment.id ? comment : existingComment\n );\n\n const updatedThread = {\n ...thread,\n updatedAt: new Date(\n Math.max(\n thread.updatedAt.getTime(),\n comment.editedAt?.getTime() || comment.createdAt.getTime()\n )\n ),\n comments: updatedComments,\n };\n return updatedThread;\n }\n\n return thread;\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyDeleteComment<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n thread: ThreadDataWithDeleteInfo<TM, CM>,\n commentId: string,\n deletedAt: Date\n): ThreadDataWithDeleteInfo<TM, CM> {\n // If the thread has been deleted, we do not delete the comment\n if (thread.deletedAt !== undefined) {\n return thread;\n }\n\n const existingComment = thread.comments.find(\n (comment) => comment.id === commentId\n );\n\n // If the comment doesn't exist in the thread, we cannot perform the deletion\n if (existingComment === undefined) {\n return thread;\n }\n\n // If the comment has been deleted since the deletion request, we do not delete the comment\n if (existingComment.deletedAt !== undefined) {\n return thread;\n }\n\n const updatedComments = thread.comments.map((comment) =>\n comment.id === commentId\n ? {\n ...comment,\n deletedAt,\n // We optimistically remove the comment body and attachments when marking it as deleted\n body: undefined,\n attachments: [],\n }\n : comment\n );\n\n // If all comments have been deleted (or there are no comments in the first\n // place), we mark the thread as deleted.\n if (updatedComments.every((comment) => comment.deletedAt !== undefined)) {\n return {\n ...thread,\n deletedAt,\n updatedAt: deletedAt,\n };\n }\n\n return {\n ...thread,\n updatedAt: deletedAt,\n comments: updatedComments,\n };\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyAddReaction<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n thread: ThreadDataWithDeleteInfo<TM, CM>,\n commentId: string,\n reaction: CommentUserReaction\n): ThreadDataWithDeleteInfo<TM, CM> {\n // If the thread has been deleted, we do not add the reaction\n if (thread.deletedAt !== undefined) {\n return thread;\n }\n\n const existingComment = thread.comments.find(\n (comment) => comment.id === commentId\n );\n\n // If the comment doesn't exist in the thread, we do not add the reaction\n if (existingComment === undefined) {\n return thread;\n }\n\n // If the comment has been deleted since the reaction addition request, we do not add the reaction\n if (existingComment.deletedAt !== undefined) {\n return thread;\n }\n\n const updatedComments = thread.comments.map((comment) =>\n comment.id === commentId\n ? {\n ...comment,\n reactions: upsertReaction(comment.reactions, reaction),\n }\n : comment\n );\n\n return {\n ...thread,\n updatedAt: new Date(\n Math.max(reaction.createdAt.getTime(), thread.updatedAt.getTime())\n ),\n comments: updatedComments,\n };\n}\n\n/** @internal Exported for unit tests only. */\nexport function applyRemoveReaction<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n thread: ThreadDataWithDeleteInfo<TM, CM>,\n commentId: string,\n emoji: string,\n userId: string,\n removedAt: Date\n): ThreadDataWithDeleteInfo<TM, CM> {\n // If the thread has been deleted, we do not remove the reaction\n if (thread.deletedAt !== undefined) {\n return thread;\n }\n\n const existingComment = thread.comments.find(\n (comment) => comment.id === commentId\n );\n\n // If the comment doesn't exist in the thread, we do not remove the reaction\n if (existingComment === undefined) {\n return thread;\n }\n\n // If the comment has been deleted since the reaction removal request, we do not remove the reaction\n if (existingComment.deletedAt !== undefined) {\n return thread;\n }\n\n const updatedComments = thread.comments.map((comment) =>\n comment.id === commentId\n ? {\n ...comment,\n reactions: comment.reactions\n .map((reaction) =>\n reaction.emoji === emoji\n ? {\n ...reaction,\n users: reaction.users.filter((user) => user.id !== userId),\n }\n : reaction\n )\n .filter((reaction) => reaction.users.length > 0), // Remove reactions with no users left\n }\n : comment\n );\n\n return {\n ...thread,\n updatedAt: new Date(\n Math.max(removedAt.getTime(), thread.updatedAt.getTime())\n ),\n comments: updatedComments,\n };\n}\n\nfunction upsertReaction(\n reactions: CommentReaction[],\n reaction: CommentUserReaction\n): CommentReaction[] {\n const existingReaction = reactions.find(\n (existingReaction) => existingReaction.emoji === reaction.emoji\n );\n\n // If the reaction doesn't exist in the comment, we add it\n if (existingReaction === undefined) {\n return [\n ...reactions,\n {\n emoji: reaction.emoji,\n createdAt: reaction.createdAt,\n users: [{ id: reaction.userId }],\n },\n ];\n }\n\n // If the reaction exists in the comment, we add the user to the reaction if they are not already in it\n if (\n existingReaction.users.some((user) => user.id === reaction.userId) === false\n ) {\n return reactions.map((existingReaction) =>\n existingReaction.emoji === reaction.emoji\n ? {\n ...existingReaction,\n users: [...existingReaction.users, { id: reaction.userId }],\n }\n : existingReaction\n );\n }\n\n return reactions;\n}\n","/**\n * Binds all methods on a class instance to \"this\". Call this from the\n * constructor if you want to be able to reference the methods like this:\n *\n * ------------------------------------------------------------------------\n *\n * class MyClass {}\n * const thing = new MyClass();\n * const getter1 = thing.someMethod; // ❌ Cannot refer to someMethod this way, because \"this\" will not be bound to \"thing\" here\n * const getter2 = thing.anotherMethod; // ❌\n *\n * ------------------------------------------------------------------------\n *\n * class MyClass {\n * constructor() {\n * // ...\n * autobind(this); // 👈\n * }\n * }\n * const thing = new MyClass();\n * const getter1 = thing.someMethod; // ✅ Now \"this\" will be correctly bound to \"thing\" inside someMethod()\n * const getter2 = thing.anotherMethod; // ✅ Now\n *\n */\nexport function autobind(self: object): void {\n const seen = new Set<string | symbol>();\n seen.add(\"constructor\"); // We'll never want to bind the constructor\n\n let obj = self.constructor.prototype as object;\n do {\n for (const key of Reflect.ownKeys(obj)) {\n if (seen.has(key)) continue;\n const descriptor = Reflect.getOwnPropertyDescriptor(obj, key);\n if (typeof descriptor?.value === \"function\") {\n seen.add(key);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call\n (self as any)[key] = (self as any)[key].bind(self);\n }\n }\n } while ((obj = Reflect.getPrototypeOf(obj)!) && obj !== Object.prototype);\n}\n","/**\n * Like Array.prototype.find(), but for iterables.\n *\n * Returns the first item in the iterable for which the predicate holds.\n * Returns undefined if item matches the predicate.\n */\nexport function find<T>(\n it: Iterable<T>,\n predicate: (value: T) => boolean\n): T | undefined {\n for (const item of it) {\n if (predicate(item)) return item;\n }\n return undefined;\n}\n\n/**\n * Counts the number of items in an iterable that match the predicate.\n */\nexport function count<T>(\n it: Iterable<T>,\n predicate: (value: T) => boolean\n): number {\n let total = 0;\n for (const item of it) {\n if (predicate(item)) total++;\n }\n return total;\n}\n","import type {\n BaseMetadata,\n InboxNotificationData,\n ThreadData,\n} from \"@liveblocks/client\";\nimport {\n getSubscriptionKey,\n isNumberOperator,\n isStartsWithOperator,\n type QueryMetadata,\n type SubscriptionData,\n type SubscriptionKey,\n} from \"@liveblocks/core\";\n\nimport type { InboxNotificationsQuery, ThreadsQuery } from \"../types\";\n\n/**\n * Creates a predicate function that will filter all ThreadData instances that\n * match the given query.\n */\nexport function makeThreadsFilter<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n query: ThreadsQuery<TM>,\n subscriptions: Record<SubscriptionKey, SubscriptionData> | undefined\n): (thread: ThreadData<TM, CM>) => boolean {\n return (thread: ThreadData<TM, CM>) =>\n matchesThreadsQuery(thread, query, subscriptions) &&\n matchesThreadMetadata(thread, query);\n}\n\nfunction matchesThreadsQuery<TM extends BaseMetadata, CM extends BaseMetadata>(\n thread: ThreadData<TM, CM>,\n q: ThreadsQuery<TM>,\n subscriptions: Record<SubscriptionKey, SubscriptionData> | undefined\n) {\n let subscription = undefined;\n if (subscriptions) {\n subscription = subscriptions?.[getSubscriptionKey(\"thread\", thread.id)];\n }\n\n return (\n (q.resolved === undefined || thread.resolved === q.resolved) &&\n (q.subscribed === undefined ||\n (q.subscribed === true && subscription !== undefined) ||\n (q.subscribed === false && subscription === undefined))\n );\n}\n\nfunction matchesThreadMetadata<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(thread: ThreadData<TM, CM>, q: ThreadsQuery<TM>) {\n // Boolean logic: query.metadata? => all metadata matches\n const metadata = thread.metadata;\n return (\n q.metadata === undefined ||\n Object.entries(q.metadata).every(\n ([key, op]: [keyof TM, QueryMetadata<TM>[keyof TM] | undefined]) =>\n // Ignore explicit-undefined filters\n // Boolean logic: op? => value matches the operator\n op === undefined || matchesOperator(metadata[key], op)\n )\n );\n}\n\nfunction matchesOperator(\n value: BaseMetadata[string],\n op:\n | Exclude<BaseMetadata[string], undefined>\n | { startsWith: string }\n | {\n lt?: number;\n gt?: number;\n lte?: number;\n gte?: number;\n }\n | null\n) {\n if (op === null) {\n // If the operator is `null`, we're doing an explicit query for absence\n return value === undefined;\n } else if (isStartsWithOperator(op)) {\n return typeof value === \"string\" && value.startsWith(op.startsWith);\n } else if (isNumberOperator(op)) {\n return typeof value === \"number\" && matchesNumberOperator(value, op);\n } else {\n return value === op;\n }\n}\n\nfunction matchesNumberOperator(\n value: number,\n op: {\n lt?: number;\n gt?: number;\n lte?: number;\n gte?: number;\n }\n) {\n return (\n (op.lt === undefined || value < op.lt) &&\n (op.gt === undefined || value > op.gt) &&\n (op.lte === undefined || value <= op.lte) &&\n (op.gte === undefined || value >= op.gte)\n );\n}\n\nexport function makeInboxNotificationsFilter(\n query: InboxNotificationsQuery\n): (inboxNotification: InboxNotificationData) => boolean {\n return (inboxNotification: InboxNotificationData) =>\n matchesInboxNotificationsQuery(inboxNotification, query);\n}\n\nfunction matchesInboxNotificationsQuery(\n inboxNotification: InboxNotificationData,\n q: InboxNotificationsQuery\n) {\n return (\n (q.roomId === undefined || q.roomId === inboxNotification.roomId) &&\n (q.kind === undefined || q.kind === inboxNotification.kind)\n );\n}\n","import type {\n BaseMetadata,\n SubscriptionData,\n SubscriptionKey,\n ThreadData,\n ThreadDataWithDeleteInfo,\n ThreadDeleteInfo,\n} from \"@liveblocks/core\";\nimport { batch, MutableSignal, SortedList } from \"@liveblocks/core\";\n\nimport { makeThreadsFilter } from \"./lib/querying\";\nimport type { ThreadsQuery } from \"./types\";\n\nfunction sanitizeThread<TM extends BaseMetadata, CM extends BaseMetadata>(\n thread: ThreadDataWithDeleteInfo<TM, CM>\n): ThreadDataWithDeleteInfo<TM, CM> {\n // First, if a thread has a deletedAt date, it should not have any comments\n if (thread.deletedAt) {\n // Thread is deleted, it should wipe all comments\n if (thread.comments.length > 0) {\n return { ...thread, comments: [] };\n }\n }\n\n // Otherwise, if a thread is not deleted, it _should_ have at least one non-deleted comment\n const hasComment = thread.comments.some((c) => !c.deletedAt);\n if (!hasComment) {\n // Delete it after all if it doesn't have at least one comment\n return { ...thread, deletedAt: new Date(), comments: [] };\n }\n\n return thread;\n}\n\nexport type ReadonlyThreadDB<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = Omit<ThreadDB<TM, CM>, \"upsert\" | \"delete\" | \"signal\">;\n\n/**\n * This class implements a lightweight, in-memory, \"database\" for all Thread\n * instances.\n *\n * It exposes the following methods:\n *\n * - upsert: To add/update a thread\n * - upsertIfNewer: To add/update a thread. Only update an existing thread if\n * its newer\n * - delete: To mark existing threads as deleted\n * - get: To get any non-deleted thread\n * - getEvenIfDeleted: To get a thread which is possibly deleted\n * - findMany: To filter an ordered list of non-deleted threads\n * - clone: To clone the DB to mutate it further. This is used to mix in\n * optimistic updates without losing the original thread contents.\n *\n */\nexport class ThreadDB<TM extends BaseMetadata, CM extends BaseMetadata> {\n #byId: Map<string, ThreadDataWithDeleteInfo<TM, CM>>;\n #asc: SortedList<ThreadData<TM, CM>>;\n #desc: SortedList<ThreadData<TM, CM>>;\n\n // This signal will be notified on every mutation\n public readonly signal: MutableSignal<this>;\n\n constructor() {\n this.#asc = SortedList.from<ThreadData<TM, CM>>([], (t1, t2) => {\n const d1 = t1.createdAt;\n const d2 = t2.createdAt;\n return d1 < d2 ? true : d1 === d2 ? t1.id < t2.id : false;\n });\n\n this.#desc = SortedList.from<ThreadData<TM, CM>>([], (t1, t2) => {\n const d2 = t2.updatedAt;\n const d1 = t1.updatedAt;\n return d2 < d1 ? true : d2 === d1 ? t2.id < t1.id : false;\n });\n\n this.#byId = new Map();\n\n this.signal = new MutableSignal(this);\n }\n\n //\n // Public APIs\n //\n\n public clone(): ThreadDB<TM, CM> {\n const newPool = new ThreadDB<TM, CM>();\n newPool.#byId = new Map(this.#byId);\n newPool.#asc = this.#asc.clone();\n newPool.#desc = this.#desc.clone();\n return newPool;\n }\n\n /** Returns an existing thread by ID. Will never return a deleted thread. */\n public get(threadId: string): ThreadData<TM, CM> | undefined {\n const thread = this.getEvenIfDeleted(threadId);\n return thread?.deletedAt ? undefined : thread;\n }\n\n /** Returns the (possibly deleted) thread by ID. */\n public getEvenIfDeleted(\n threadId: string\n ): ThreadDataWithDeleteInfo<TM, CM> | undefined {\n return this.#byId.get(threadId);\n }\n\n /** Adds or updates a thread in the DB. If the newly given thread is a deleted one, it will get deleted. */\n public upsert(thread: ThreadDataWithDeleteInfo<TM, CM>): void {\n this.signal.mutate(() => {\n thread = sanitizeThread(thread);\n\n const id = thread.id;\n\n const toRemove = this.#byId.get(id);\n if (toRemove) {\n // Don't do anything if the existing thread is already deleted!\n if (toRemove.deletedAt) return false;\n\n this.#asc.remove(toRemove);\n this.#desc.remove(toRemove);\n }\n\n if (!thread.deletedAt) {\n this.#asc.add(thread);\n this.#desc.add(thread);\n }\n this.#byId.set(id, thread);\n return true;\n });\n }\n\n /** Like .upsert(), except it won't update if a thread by this ID already exists. */\n // TODO Consider renaming this to just .upsert(). I'm not sure if we really\n // TODO need the raw .upsert(). Would be nice if this behavior was the default.\n public upsertIfNewer(thread: ThreadDataWithDeleteInfo<TM, CM>): void {\n const existing = this.get(thread.id);\n if (!existing || thread.updatedAt >= existing.updatedAt) {\n this.upsert(thread);\n }\n }\n\n public applyDelta(\n newThreads: ThreadData<TM, CM>[],\n deletedThreads: ThreadDeleteInfo[]\n ): void {\n batch(() => {\n // Add new threads or update existing threads if the existing thread is older than the new thread.\n for (const thread of newThreads) {\n this.upsertIfNewer(thread);\n }\n\n // Mark threads in the deletedThreads list as deleted\n for (const { id, deletedAt } of deletedThreads) {\n const existing = this.getEvenIfDeleted(id);\n if (!existing) continue;\n this.delete(id, deletedAt);\n }\n });\n }\n\n /**\n * Marks a thread as deleted. It will no longer pop up in .findMany()\n * queries, but it can still be accessed via `.getEvenIfDeleted()`.\n */\n public delete(threadId: string, deletedAt: Date): void {\n const existing = this.#byId.get(threadId);\n if (existing && !existing.deletedAt) {\n this.upsert({ ...existing, deletedAt, updatedAt: deletedAt });\n }\n }\n\n /**\n * Returns all threads matching a given roomId and query. If roomId is not\n * specified, it will return all threads matching the query, across all\n * rooms.\n *\n * Returns the results in the requested order. Please note:\n * 'asc' means by createdAt ASC\n * 'desc' means by updatedAt DESC\n *\n * Will never return deleted threads in the result.\n *\n * Subscriptions are needed to filter threads based on the user's subscriptions.\n */\n public findMany(\n // TODO: Implement caching here\n roomId: string | undefined,\n query: ThreadsQuery<TM> | undefined,\n direction: \"asc\" | \"desc\",\n subscriptions?: Record<SubscriptionKey, SubscriptionData>\n ): ThreadData<TM, CM>[] {\n const index = direction === \"desc\" ? this.#desc : this.#asc;\n const crit: ((thread: ThreadData<TM, CM>) => boolean)[] = [];\n if (roomId !== undefined) {\n crit.push((t) => t.roomId === roomId);\n }\n if (query !== undefined) {\n crit.push(makeThreadsFilter(query, subscriptions));\n }\n return Array.from(index.filter((t) => crit.every((pred) => pred(t))));\n }\n}\n","import type {\n BaseMetadata,\n BaseUserMeta,\n BroadcastOptions,\n Client,\n CommentData,\n History,\n Json,\n JsonObject,\n LiveObject,\n LostConnectionEvent,\n LsonObject,\n OthersEvent,\n Room,\n Status,\n ThreadData,\n User,\n} from \"@liveblocks/client\";\nimport { shallow } from \"@liveblocks/client\";\nimport type {\n AsyncResult,\n CommentsEventServerMsg,\n DCM,\n DE,\n DP,\n DS,\n DTM,\n DU,\n EnterOptions,\n IYjsProvider,\n LiveblocksErrorContext,\n MentionData,\n OpaqueClient,\n RoomEventMessage,\n RoomSubscriptionSettings,\n SignalType,\n TextEditorType,\n ToImmutable,\n UnsubscribeCallback,\n} from \"@liveblocks/core\";\nimport {\n assert,\n console,\n createCommentId,\n createThreadId,\n DefaultMap,\n errorIf,\n getSubscriptionKey,\n HttpError,\n kInternal,\n makePoller,\n ServerMsgCode,\n stableStringify,\n} from \"@liveblocks/core\";\nimport type { Context } from \"react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n version as reactVersion,\n} from \"react\";\n\nimport { config } from \"./config\";\nimport {\n RoomContext,\n useClient,\n useIsInsideRoom,\n useRoomOrNull,\n} from \"./contexts\";\nimport { ensureNotServerSide } from \"./lib/ssr\";\nimport { useInitial } from \"./lib/use-initial\";\nimport { useLatest } from \"./lib/use-latest\";\nimport { use } from \"./lib/use-polyfill\";\nimport {\n createSharedContext,\n getUmbrellaStoreForClient,\n LiveblocksProviderWithClient,\n} from \"./liveblocks\";\nimport type {\n AttachmentUrlAsyncResult,\n CommentReactionOptions,\n CreateCommentOptions,\n CreateThreadOptions,\n DeleteCommentOptions,\n EditCommentMetadataOptions,\n EditCommentOptions,\n EditThreadMetadataOptions,\n HistoryVersionDataAsyncResult,\n HistoryVersionsAsyncResult,\n HistoryVersionsAsyncSuccess,\n MutationContext,\n OmitFirstArg,\n RoomContextBundle,\n RoomProviderProps,\n RoomSubscriptionSettingsAsyncResult,\n RoomSubscriptionSettingsAsyncSuccess,\n SearchCommentsAsyncResult,\n ThreadsAsyncResult,\n ThreadsAsyncSuccess,\n ThreadSubscription,\n UseSearchCommentsOptions,\n UseThreadsOptions,\n} from \"./types\";\nimport type { UmbrellaStore } from \"./umbrella-store\";\nimport { makeRoomThreadsQueryKey } from \"./umbrella-store\";\nimport { useScrollToCommentOnLoadEffect } from \"./use-scroll-to-comment-on-load-effect\";\nimport { useSignal } from \"./use-signal\";\nimport { useSyncExternalStoreWithSelector } from \"./use-sync-external-store-with-selector\";\n\nconst noop = () => {};\nconst identity: <T>(x: T) => T = (x) => x;\n\nconst STABLE_EMPTY_LIST = Object.freeze([]);\n\n// Don't try to inline this. This function is intended to be a stable\n// reference, to avoid a useCallback() wrapper.\nfunction alwaysEmptyList() {\n return STABLE_EMPTY_LIST;\n}\n\n// Don't try to inline this. This function is intended to be a stable\n// reference, to avoid a useCallback() wrapper.\nfunction alwaysNull() {\n return null;\n}\n\nfunction selectorFor_useOthersConnectionIds(\n others: readonly User<JsonObject, BaseUserMeta>[]\n): number[] {\n return others.map((user) => user.connectionId);\n}\n\nfunction makeMutationContext<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(room: Room<P, S, U, E, TM, CM>): MutationContext<P, S, U> {\n const cannotUseUntil = \"This mutation cannot be used until\";\n const needsPresence = `${cannotUseUntil} connected to the Liveblocks room`;\n const needsStorage = `${cannotUseUntil} storage has been loaded`;\n\n return {\n get storage() {\n const mutableRoot = room.getStorageSnapshot();\n if (mutableRoot === null) {\n throw new Error(needsStorage);\n }\n return mutableRoot;\n },\n\n get self() {\n const self = room.getSelf();\n if (self === null) {\n throw new Error(needsPresence);\n }\n return self;\n },\n\n get others() {\n const others = room.getOthers();\n if (room.getSelf() === null) {\n throw new Error(needsPresence);\n }\n return others;\n },\n\n setMyPresence: room.updatePresence,\n };\n}\n\nfunction getCurrentUserId(client: Client): string {\n const userId = client[kInternal].currentUserId.get();\n if (userId === undefined) {\n return \"anonymous\";\n }\n return userId;\n}\n\nconst _extras = new WeakMap<\n OpaqueClient,\n ReturnType<typeof makeRoomExtrasForClient>\n>();\nconst _bundles = new WeakMap<\n OpaqueClient,\n RoomContextBundle<\n JsonObject,\n LsonObject,\n BaseUserMeta,\n Json,\n BaseMetadata,\n BaseMetadata\n >\n>();\n\nfunction getOrCreateRoomContextBundle<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: OpaqueClient): RoomContextBundle<P, S, U, E, TM, CM> {\n let bundle = _bundles.get(client);\n if (!bundle) {\n bundle = makeRoomContextBundle(client);\n _bundles.set(client, bundle);\n }\n return bundle as unknown as RoomContextBundle<P, S, U, E, TM, CM>;\n}\n\n// TODO: Likely a better / more clear name for this helper will arise. I'll\n// rename this later. All of these are implementation details to support inbox\n// notifications on a per-client basis.\nfunction getRoomExtrasForClient<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: OpaqueClient) {\n let extras = _extras.get(client);\n if (!extras) {\n extras = makeRoomExtrasForClient(client);\n _extras.set(client, extras);\n }\n\n return extras as unknown as Omit<typeof extras, \"store\"> & {\n store: UmbrellaStore<TM, CM>;\n };\n}\n\nfunction makeRoomExtrasForClient(client: OpaqueClient) {\n const store = getUmbrellaStoreForClient(client);\n\n function onMutationFailure(\n optimisticId: string,\n context: LiveblocksErrorContext & { roomId: string },\n innerError: Error\n ): void {\n store.optimisticUpdates.remove(optimisticId);\n\n // All mutation failures are expected to be HTTP errors ultimately - only\n // ever notify the user about those.\n if (innerError instanceof HttpError) {\n // Always log details about 403 Forbidden errors to the console as well\n if (innerError.status === 403) {\n const detailedMessage = [\n innerError.message,\n innerError.details?.suggestion,\n innerError.details?.docs,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n console.error(detailedMessage);\n }\n\n client[kInternal].emitError(context, innerError);\n } else {\n // In this context, a non-HTTP error is unexpected and should be\n // considered a bug we should get fixed. Don't notify the user about it.\n throw innerError;\n }\n }\n\n const threadsPollersByRoomId = new DefaultMap((roomId: string) =>\n makePoller(\n async (signal) => {\n try {\n return await store.fetchRoomThreadsDeltaUpdate(roomId, signal);\n } catch (err) {\n console.warn(`Polling new threads for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n throw err;\n }\n },\n config.ROOM_THREADS_POLL_INTERVAL,\n { maxStaleTimeMs: config.ROOM_THREADS_MAX_STALE_TIME }\n )\n );\n\n const versionsPollersByRoomId = new DefaultMap((roomId: string) =>\n makePoller(\n async (signal) => {\n try {\n return await store.fetchRoomVersionsDeltaUpdate(roomId, signal);\n } catch (err) {\n console.warn(`Polling new history versions for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n throw err;\n }\n },\n config.HISTORY_VERSIONS_POLL_INTERVAL,\n { maxStaleTimeMs: config.HISTORY_VERSIONS_MAX_STALE_TIME }\n )\n );\n\n const roomSubscriptionSettingsPollersByRoomId = new DefaultMap(\n (roomId: string) =>\n makePoller(\n async (signal) => {\n try {\n return await store.refreshRoomSubscriptionSettings(roomId, signal);\n } catch (err) {\n console.warn(`Polling subscription settings for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n throw err;\n }\n },\n config.ROOM_SUBSCRIPTION_SETTINGS_POLL_INTERVAL,\n { maxStaleTimeMs: config.ROOM_SUBSCRIPTION_SETTINGS_MAX_STALE_TIME }\n )\n );\n\n return {\n store,\n onMutationFailure,\n pollThreadsForRoomId: (roomId: string) => {\n const threadsPoller = threadsPollersByRoomId.getOrCreate(roomId);\n\n // If there's a threads poller for this room, immediately trigger it\n if (threadsPoller) {\n threadsPoller.markAsStale();\n threadsPoller.pollNowIfStale();\n }\n },\n getOrCreateThreadsPollerForRoomId: threadsPollersByRoomId.getOrCreate.bind(\n threadsPollersByRoomId\n ),\n getOrCreateVersionsPollerForRoomId:\n versionsPollersByRoomId.getOrCreate.bind(versionsPollersByRoomId),\n getOrCreateSubscriptionSettingsPollerForRoomId:\n roomSubscriptionSettingsPollersByRoomId.getOrCreate.bind(\n roomSubscriptionSettingsPollersByRoomId\n ),\n };\n}\n\ntype RoomLeavePair<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n room: Room<P, S, U, E, TM, CM>;\n leave: () => void;\n};\n\nfunction makeRoomContextBundle<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(client: Client<U>): RoomContextBundle<P, S, U, E, TM, CM> {\n type TRoom = Room<P, S, U, E, TM, CM>;\n\n function RoomProvider_withImplicitLiveblocksProvider(\n props: RoomProviderProps<P, S>\n ) {\n // NOTE: Normally, nesting LiveblocksProvider is not allowed. This\n // factory-bound version of the RoomProvider will create an implicit\n // LiveblocksProvider. This means that if an end user nests this\n // RoomProvider under a LiveblocksProvider context, that would be an error.\n // However, we'll allow that nesting only in this specific situation, and\n // only because this wrapper will keep the Liveblocks context and the Room\n // context consistent internally.\n return (\n <LiveblocksProviderWithClient client={client} allowNesting>\n {/* @ts-expect-error {...props} is the same type as props */}\n <RoomProvider {...props} />\n </LiveblocksProviderWithClient>\n );\n }\n\n const shared = createSharedContext<U>(client);\n\n const bundle: RoomContextBundle<P, S, U, E, TM, CM> = {\n RoomContext: RoomContext as Context<TRoom | null>,\n RoomProvider: RoomProvider_withImplicitLiveblocksProvider,\n\n useRoom,\n useStatus,\n\n useBroadcastEvent,\n useOthersListener,\n useLostConnectionListener,\n useEventListener,\n\n useHistory,\n useUndo,\n useRedo,\n useCanRedo,\n useCanUndo,\n\n useStorageRoot,\n useStorage,\n\n useSelf,\n useMyPresence,\n useUpdateMyPresence,\n useOthers,\n useOthersMapped,\n useOthersConnectionIds,\n useOther,\n\n // prettier-ignore\n useMutation: useMutation as RoomContextBundle<P, S, U, E, TM, CM>[\"useMutation\"],\n\n useThreads,\n useSearchComments,\n\n // prettier-ignore\n useCreateThread: useCreateThread as RoomContextBundle<P, S, U, E, TM, CM>[\"useCreateThread\"],\n\n useDeleteThread,\n useEditThreadMetadata,\n useMarkThreadAsResolved,\n useMarkThreadAsUnresolved,\n useSubscribeToThread,\n useUnsubscribeFromThread,\n useCreateComment,\n useEditComment,\n useEditCommentMetadata,\n useDeleteComment,\n useAddReaction,\n useRemoveReaction,\n useMarkThreadAsRead,\n useThreadSubscription,\n useAttachmentUrl,\n\n useHistoryVersions,\n useHistoryVersionData,\n\n useRoomSubscriptionSettings,\n useUpdateRoomSubscriptionSettings,\n\n ...shared.classic,\n\n suspense: {\n RoomContext: RoomContext as Context<TRoom | null>,\n RoomProvider: RoomProvider_withImplicitLiveblocksProvider,\n\n useRoom,\n useStatus,\n\n useBroadcastEvent,\n useOthersListener,\n useLostConnectionListener,\n useEventListener,\n\n useHistory,\n useUndo,\n useRedo,\n useCanRedo,\n useCanUndo,\n\n useStorageRoot,\n useStorage: useStorageSuspense,\n\n useSelf: useSelfSuspense,\n useMyPresence,\n useUpdateMyPresence,\n useOthers: useOthersSuspense,\n useOthersMapped: useOthersMappedSuspense,\n useOthersConnectionIds: useOthersConnectionIdsSuspense,\n useOther: useOtherSuspense,\n\n // prettier-ignore\n useMutation: useMutation as RoomContextBundle<P, S, U, E, TM, CM>[\"suspense\"][\"useMutation\"],\n\n useThreads: useThreadsSuspense,\n\n // prettier-ignore\n useCreateThread: useCreateThread as RoomContextBundle<P, S, U, E, TM, CM>[\"suspense\"][\"useCreateThread\"],\n\n useDeleteThread,\n useEditThreadMetadata,\n useMarkThreadAsResolved,\n useMarkThreadAsUnresolved,\n useSubscribeToThread,\n useUnsubscribeFromThread,\n useCreateComment,\n useEditComment,\n useEditCommentMetadata,\n useDeleteComment,\n useAddReaction,\n useRemoveReaction,\n useMarkThreadAsRead,\n useThreadSubscription,\n useAttachmentUrl: useAttachmentUrlSuspense,\n\n // TODO: useHistoryVersionData: useHistoryVersionDataSuspense,\n useHistoryVersions: useHistoryVersionsSuspense,\n\n useRoomSubscriptionSettings: useRoomSubscriptionSettingsSuspense,\n useUpdateRoomSubscriptionSettings,\n\n ...shared.suspense,\n },\n };\n\n return Object.defineProperty(bundle, kInternal, {\n enumerable: false,\n });\n}\n\nfunction RoomProvider<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(props: RoomProviderProps<P, S>) {\n const client = useClient<U>();\n const [cache] = useState(\n () => new Map<string, RoomLeavePair<P, S, U, E, TM, CM>>()\n );\n\n // Produce a version of client.enterRoom() that when called for the same\n // room ID multiple times, will not keep producing multiple leave\n // functions, but instead return the cached one.\n const stableEnterRoom: typeof client.enterRoom<P, S, E, TM, CM> = useCallback(\n (\n roomId: string,\n options: EnterOptions<P, S>\n ): RoomLeavePair<P, S, U, E, TM, CM> => {\n const cached = cache.get(roomId);\n if (cached) return cached;\n\n const rv = client.enterRoom<P, S, E, TM, CM>(roomId, options);\n\n // Wrap the leave function to also delete the cached value\n const origLeave = rv.leave;\n rv.leave = () => {\n origLeave();\n cache.delete(roomId);\n };\n\n cache.set(roomId, rv);\n return rv;\n },\n [client, cache]\n );\n\n //\n // RATIONALE:\n // At the \"Outer\" RoomProvider level, we keep a cache and produce\n // a stableEnterRoom function, which we pass down to the real \"Inner\"\n // RoomProvider level.\n //\n // The purpose is to ensure that if `stableEnterRoom(\"my-room\")` is called\n // multiple times for the same room ID, it will always return the exact same\n // (cached) value, so that in total only a single \"leave\" function gets\n // produced and registered in the client.\n //\n // If we didn't use this cache, then in React StrictMode\n // stableEnterRoom(\"my-room\") might get called multiple (at least 4) times,\n // causing more leave functions to be produced in the client, some of which\n // we cannot get a hold on (because StrictMode would discard those results by\n // design). This would make it appear to the Client that the Room is still in\n // use by some party that hasn't called `leave()` on it yet, thus causing the\n // Room to not be freed and destroyed when the component unmounts later.\n //\n return (\n <RoomProviderInner<P, S, U, E, TM, CM>\n {...(props as any)}\n stableEnterRoom={stableEnterRoom}\n />\n );\n}\n\ntype EnterRoomType<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = (\n roomId: string,\n options: EnterOptions<P, S>\n) => RoomLeavePair<P, S, U, E, TM, CM>;\n\n/** @internal */\nfunction RoomProviderInner<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n>(\n props: RoomProviderProps<P, S> & {\n stableEnterRoom: EnterRoomType<P, S, U, E, TM, CM>;\n }\n) {\n const client = useClient<U>();\n const { id: roomId, stableEnterRoom } = props;\n\n if (process.env.NODE_ENV !== \"production\") {\n if (!roomId) {\n throw new Error(\n \"RoomProvider id property is required. For more information: https://liveblocks.io/docs/errors/liveblocks-react/RoomProvider-id-property-is-required\"\n );\n }\n\n if (typeof roomId !== \"string\") {\n throw new Error(\"RoomProvider id property should be a string.\");\n }\n\n const majorReactVersion = parseInt(reactVersion) || 1;\n const requiredVersion = 18;\n errorIf(\n majorReactVersion < requiredVersion,\n `React ${requiredVersion} or higher is required (you’re on ${reactVersion})`\n );\n }\n\n // Note: We'll hold on to the initial value given here, and ignore any\n // changes to this argument in subsequent renders, except when roomId changes\n const frozenProps = useInitial(\n {\n initialPresence: props.initialPresence,\n initialStorage: props.initialStorage,\n autoConnect: props.autoConnect ?? typeof window !== \"undefined\",\n engine: props.engine,\n },\n roomId\n ) as EnterOptions<P, S>;\n\n const [{ room }, setRoomLeavePair] = useState(() =>\n stableEnterRoom(roomId, {\n ...frozenProps,\n autoConnect: false, // Deliberately using false here on the first render, see below\n })\n );\n\n useEffect(() => {\n const { store } = getRoomExtrasForClient(client);\n\n async function handleCommentEvent(message: CommentsEventServerMsg) {\n // If thread deleted event is received, we remove the thread from the local cache\n // no need for more processing\n if (message.type === ServerMsgCode.THREAD_DELETED) {\n store.deleteThread(message.threadId, null);\n return;\n }\n\n // TODO: Error handling\n const info = await room.getThread(message.threadId);\n\n // If no thread info was returned (i.e., 404), we remove the thread and relevant inbox notifications from local cache.\n if (!info.thread) {\n store.deleteThread(message.threadId, null);\n return;\n }\n const {\n thread,\n inboxNotification: maybeNotification,\n subscription: maybeSubscription,\n } = info;\n\n const existingThread = store.outputs.threads\n .get()\n .getEvenIfDeleted(message.threadId);\n\n switch (message.type) {\n case ServerMsgCode.COMMENT_EDITED:\n case ServerMsgCode.THREAD_METADATA_UPDATED:\n case ServerMsgCode.THREAD_UPDATED:\n case ServerMsgCode.COMMENT_REACTION_ADDED:\n case ServerMsgCode.COMMENT_REACTION_REMOVED:\n case ServerMsgCode.COMMENT_DELETED:\n case ServerMsgCode.COMMENT_METADATA_UPDATED:\n // If the thread doesn't exist in the local cache, we do not update it with the server data as an optimistic update could have deleted the thread locally.\n if (!existingThread) break;\n\n store.updateThreadifications(\n [thread],\n maybeNotification ? [maybeNotification] : [],\n maybeSubscription ? [maybeSubscription] : []\n );\n break;\n\n case ServerMsgCode.COMMENT_CREATED:\n store.updateThreadifications(\n [thread],\n maybeNotification ? [maybeNotification] : [],\n maybeSubscription ? [maybeSubscription] : []\n );\n break;\n default:\n break;\n }\n }\n\n return room.events.comments.subscribe(\n (message) => void handleCommentEvent(message)\n );\n }, [client, room]);\n\n useEffect(() => {\n const pair = stableEnterRoom(roomId, frozenProps);\n\n setRoomLeavePair(pair);\n const { room, leave } = pair;\n\n // In React, it's important to start connecting to the room as an effect,\n // rather than doing this during the initial render. This means that\n // during the initial render (both on the server-side, and on the first\n // hydration on the client-side), the value of the `useStatus()` hook\n // will correctly be \"initial\", and transition to \"connecting\" as an\n // effect.\n if (frozenProps.autoConnect) {\n room.connect();\n }\n\n return () => {\n leave();\n };\n }, [roomId, frozenProps, stableEnterRoom]);\n\n return (\n <RoomContext.Provider value={room}>{props.children}</RoomContext.Provider>\n );\n}\n\nfunction useRoom<\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n>(options?: { allowOutsideRoom: false }): Room<P, S, U, E, TM, CM>;\nfunction useRoom<\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n>(options: { allowOutsideRoom: boolean }): Room<P, S, U, E, TM, CM> | null;\nfunction useRoom<\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n>(options?: { allowOutsideRoom: boolean }): Room<P, S, U, E, TM, CM> | null {\n const room = useRoomOrNull<P, S, U, E, TM, CM>();\n if (room === null && !options?.allowOutsideRoom) {\n throw new Error(\"RoomProvider is missing from the React tree.\");\n }\n return room;\n}\n\n/**\n * Returns the current connection status for the Room, and triggers\n * a re-render whenever it changes. Can be used to render a status badge.\n */\nfunction useStatus(): Status {\n const room = useRoom();\n const subscribe = room.events.status.subscribe;\n const getSnapshot = room.getStatus;\n const getServerSnapshot = room.getStatus;\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useReportTextEditor(editor: TextEditorType, rootKey: string): void {\n const isReported = useRef<boolean>(false);\n const room = useRoom();\n\n useEffect(() => {\n // We use a \"locker\" reference to avoid to spam / harass our backend\n // and to not add / remove subscribers in case when the text editor type\n // has been already reported.\n if (isReported.current) {\n return;\n }\n\n const unsubscribe = room.events.status.subscribe((status: Status): void => {\n if (status === \"connected\" && !isReported.current) {\n isReported.current = true;\n // We do not catch because this method never throw (e.g `rawPost`)\n void room[kInternal].reportTextEditor(editor, rootKey);\n }\n });\n\n return unsubscribe;\n }, [room, editor, rootKey]);\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useYjsProvider(): IYjsProvider | undefined {\n const room = useRoom();\n\n const subscribe = useCallback(\n (onStoreChange: () => void): UnsubscribeCallback => {\n return room[kInternal].yjsProviderDidChange.subscribe(onStoreChange);\n },\n [room]\n );\n\n const getSnapshot = useCallback((): IYjsProvider | undefined => {\n return room[kInternal].getYjsProvider();\n }, [room]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useCreateTextMention(): (\n mentionId: string,\n mention: MentionData\n) => void {\n const room = useRoom();\n return useCallback(\n (mentionId: string, mention: MentionData): void => {\n room[kInternal]\n .createTextMention(mentionId, mention)\n .catch((err): void => {\n console.error(\n `Cannot create text mention for mention '${mentionId}'`,\n err\n );\n });\n },\n [room]\n );\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useDeleteTextMention(): (mentionId: string) => void {\n const room = useRoom();\n return useCallback(\n (mentionId: string): void => {\n room[kInternal].deleteTextMention(mentionId).catch((err): void => {\n console.error(`Cannot delete text mention '${mentionId}'`, err);\n });\n },\n [room]\n );\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useResolveMentionSuggestions() {\n const client = useClient();\n return client[kInternal].resolveMentionSuggestions;\n}\n\n/** @private - Internal API, do not rely on it. */\nfunction useMentionSuggestionsCache() {\n const client = useClient();\n return client[kInternal].mentionSuggestionsCache;\n}\n\nfunction useBroadcastEvent<E extends Json>(): (\n event: E,\n options?: BroadcastOptions\n) => void {\n const room = useRoom<never, never, never, E, never>();\n return useCallback(\n (\n event: E,\n options: BroadcastOptions = { shouldQueueEventIfNotReady: false }\n ) => {\n room.broadcastEvent(event, options);\n },\n [room]\n );\n}\n\nfunction useOthersListener<P extends JsonObject, U extends BaseUserMeta>(\n callback: (event: OthersEvent<P, U>) => void\n) {\n const room = useRoom<P, never, U, never, never>();\n const savedCallback = useLatest(callback);\n useEffect(\n () => room.events.others.subscribe((event) => savedCallback.current(event)),\n [room, savedCallback]\n );\n}\n\n/**\n * Get informed when reconnecting to the Liveblocks servers is taking\n * longer than usual. This typically is a sign of a client that has lost\n * internet connectivity.\n *\n * This isn't problematic (because the Liveblocks client is still trying to\n * reconnect), but it's typically a good idea to inform users about it if\n * the connection takes too long to recover.\n *\n * @example\n * useLostConnectionListener(event => {\n * if (event === 'lost') {\n * toast.warn('Reconnecting to the Liveblocks servers is taking longer than usual...')\n * } else if (event === 'failed') {\n * toast.warn('Reconnecting to the Liveblocks servers failed.')\n * } else if (event === 'restored') {\n * toast.clear();\n * }\n * })\n */\nfunction useLostConnectionListener(\n callback: (event: LostConnectionEvent) => void\n): void {\n const room = useRoom();\n const savedCallback = useLatest(callback);\n useEffect(\n () =>\n room.events.lostConnection.subscribe((event) =>\n savedCallback.current(event)\n ),\n [room, savedCallback]\n );\n}\n\nfunction useEventListener<\n P extends JsonObject,\n U extends BaseUserMeta,\n E extends Json,\n>(callback: (data: RoomEventMessage<P, U, E>) => void): void {\n const room = useRoom<P, never, U, E, never>();\n const savedCallback = useLatest(callback);\n useEffect(() => {\n const listener = (eventData: RoomEventMessage<P, U, E>) => {\n savedCallback.current(eventData);\n };\n\n return room.events.customEvent.subscribe(listener);\n }, [room, savedCallback]);\n}\n\n/**\n * Returns the room.history\n */\nfunction useHistory(): History {\n return useRoom().history;\n}\n\n/**\n * Returns a function that undoes the last operation executed by the current\n * client. It does not impact operations made by other clients.\n */\nfunction useUndo(): () => void {\n return useHistory().undo;\n}\n\n/**\n * Returns a function that redoes the last operation executed by the current\n * client. It does not impact operations made by other clients.\n */\nfunction useRedo(): () => void {\n return useHistory().redo;\n}\n\n/**\n * Returns whether there are any operations to undo.\n */\nfunction useCanUndo(): boolean {\n const room = useRoom();\n const subscribe = room.events.history.subscribe;\n const canUndo = room.history.canUndo;\n return useSyncExternalStore(subscribe, canUndo, canUndo);\n}\n\n/**\n * Returns whether there are any operations to redo.\n */\nfunction useCanRedo(): boolean {\n const room = useRoom();\n const subscribe = room.events.history.subscribe;\n const canRedo = room.history.canRedo;\n return useSyncExternalStore(subscribe, canRedo, canRedo);\n}\n\nfunction useSelf<P extends JsonObject, U extends BaseUserMeta>(): User<\n P,\n U\n> | null;\nfunction useSelf<P extends JsonObject, U extends BaseUserMeta, T>(\n selector: (me: User<P, U>) => T,\n isEqual?: (prev: T | null, curr: T | null) => boolean\n): T | null;\nfunction useSelf<P extends JsonObject, U extends BaseUserMeta, T>(\n maybeSelector?: (me: User<P, U>) => T,\n isEqual?: (prev: T | null, curr: T | null) => boolean\n): T | User<P, U> | null {\n type Snapshot = User<P, U> | null;\n type Selection = T | null;\n\n const room = useRoom<P, never, U, never, never>();\n const subscribe = room.events.self.subscribe;\n const getSnapshot: () => Snapshot = room.getSelf;\n\n const selector = maybeSelector ?? (identity as (me: User<P, U>) => T);\n const wrappedSelector = useCallback(\n (me: Snapshot): Selection => (me !== null ? selector(me) : null),\n [selector]\n );\n\n const getServerSnapshot = alwaysNull;\n\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getServerSnapshot,\n wrappedSelector,\n isEqual\n );\n}\n\nfunction useMyPresence<P extends JsonObject>(): [\n P,\n (patch: Partial<P>, options?: { addToHistory: boolean }) => void,\n] {\n const room = useRoom<P, never, never, never, never>();\n const subscribe = room.events.myPresence.subscribe;\n const getSnapshot = room.getPresence;\n const presence = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const setPresence = room.updatePresence;\n return [presence, setPresence];\n}\n\nfunction useUpdateMyPresence<P extends JsonObject>(): (\n patch: Partial<P>,\n options?: { addToHistory: boolean }\n) => void {\n return useRoom<P, never, never, never, never>().updatePresence;\n}\n\nfunction useOthers<\n P extends JsonObject,\n U extends BaseUserMeta,\n>(): readonly User<P, U>[];\nfunction useOthers<P extends JsonObject, U extends BaseUserMeta, T>(\n selector: (others: readonly User<P, U>[]) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction useOthers<P extends JsonObject, U extends BaseUserMeta, T>(\n selector?: (others: readonly User<P, U>[]) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T | readonly User<P, U>[] {\n const room = useRoom<P, never, U, never, never>();\n const subscribe = room.events.others.subscribe;\n const getSnapshot = room.getOthers;\n const getServerSnapshot = alwaysEmptyList;\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getServerSnapshot,\n selector ?? (identity as (others: readonly User<P, U>[]) => T),\n isEqual\n );\n}\n\nfunction useOthersMapped<P extends JsonObject, U extends BaseUserMeta, T>(\n itemSelector: (other: User<P, U>) => T,\n itemIsEqual?: (prev: T, curr: T) => boolean\n): ReadonlyArray<readonly [connectionId: number, data: T]> {\n const wrappedSelector = useCallback(\n (others: readonly User<P, U>[]) =>\n others.map((other) => [other.connectionId, itemSelector(other)] as const),\n [itemSelector]\n );\n\n const wrappedIsEqual = useCallback(\n (\n a: ReadonlyArray<readonly [connectionId: number, data: T]>,\n b: ReadonlyArray<readonly [connectionId: number, data: T]>\n ): boolean => {\n const eq = itemIsEqual ?? Object.is;\n return (\n a.length === b.length &&\n a.every((atuple, index) => {\n // We know btuple always exist because we checked the array length on the previous line\n const btuple = b[index]!;\n return atuple[0] === btuple[0] && eq(atuple[1], btuple[1]);\n })\n );\n },\n [itemIsEqual]\n );\n\n return useOthers(wrappedSelector, wrappedIsEqual);\n}\n\n/**\n * Returns an array of connection IDs. This matches the values you'll get by\n * using the `useOthers()` hook.\n *\n * Roughly equivalent to:\n * useOthers((others) => others.map(other => other.connectionId), shallow)\n *\n * This is useful in particular to implement efficiently rendering components\n * for each user in the room, e.g. cursors.\n *\n * @example\n * const ids = useOthersConnectionIds();\n * // [2, 4, 7]\n */\nfunction useOthersConnectionIds(): readonly number[] {\n return useOthers(selectorFor_useOthersConnectionIds, shallow);\n}\n\nconst NOT_FOUND = Symbol();\n\ntype NotFound = typeof NOT_FOUND;\n\nfunction useOther<P extends JsonObject, U extends BaseUserMeta, T>(\n connectionId: number,\n selector: (other: User<P, U>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T {\n const wrappedSelector = useCallback(\n (others: readonly User<P, U>[]) => {\n // TODO: Make this O(1) instead of O(n)?\n const other = others.find((other) => other.connectionId === connectionId);\n return other !== undefined ? selector(other) : NOT_FOUND;\n },\n [connectionId, selector]\n );\n\n const wrappedIsEqual = useCallback(\n (prev: T | NotFound, curr: T | NotFound): boolean => {\n if (prev === NOT_FOUND || curr === NOT_FOUND) {\n return prev === curr;\n }\n\n const eq = isEqual ?? Object.is;\n return eq(prev, curr);\n },\n [isEqual]\n );\n\n const other = useOthers(wrappedSelector, wrappedIsEqual);\n if (other === NOT_FOUND) {\n throw new Error(\n `No such other user with connection id ${connectionId} exists`\n );\n }\n\n return other;\n}\n\n/** @internal */\nfunction useMutableStorageRoot<S extends LsonObject>(): LiveObject<S> | null {\n const room = useRoom<never, S, never, never, never>();\n const subscribe = room.events.storageDidLoad.subscribeOnce;\n const getSnapshot = room.getStorageSnapshot;\n const getServerSnapshot = alwaysNull;\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n// NOTE: This API exists for backward compatible reasons\nfunction useStorageRoot<S extends LsonObject>(): [root: LiveObject<S> | null] {\n return [useMutableStorageRoot<S>()];\n}\n\nfunction useStorage<S extends LsonObject, T>(\n selector: (root: ToImmutable<S>) => T,\n isEqual?: (prev: T | null, curr: T | null) => boolean\n): T | null {\n type Snapshot = ToImmutable<S> | null;\n type Selection = T | null;\n\n const room = useRoom<never, S, never, never, never>();\n const rootOrNull = useMutableStorageRoot<S>();\n\n const wrappedSelector = useCallback(\n (rootOrNull: Snapshot): Selection =>\n rootOrNull !== null ? selector(rootOrNull) : null,\n [selector]\n );\n\n const subscribe = useCallback(\n (onStoreChange: () => void) =>\n rootOrNull !== null\n ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true })\n : noop,\n [room, rootOrNull]\n );\n\n const getSnapshot = useCallback((): Snapshot => {\n if (rootOrNull === null) {\n return null;\n } else {\n const root = rootOrNull;\n const imm = root.toImmutable();\n return imm;\n }\n }, [rootOrNull]);\n\n const getServerSnapshot = alwaysNull;\n\n return useSyncExternalStoreWithSelector(\n subscribe,\n getSnapshot,\n getServerSnapshot,\n wrappedSelector,\n isEqual\n );\n}\n\nfunction useMutation<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n F extends (context: MutationContext<P, S, U>, ...args: any[]) => any,\n>(callback: F, deps: readonly unknown[]): OmitFirstArg<F> {\n const room = useRoom<P, S, U, E, TM, CM>();\n return useMemo(\n () => {\n return ((...args) =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n room.batch(() =>\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n callback(\n makeMutationContext<P, S, U, E, TM, CM>(room),\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n ...args\n )\n )) as OmitFirstArg<F>;\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [room, ...deps]\n );\n}\n\nfunction useThreads<TM extends BaseMetadata, CM extends BaseMetadata>(\n options: UseThreadsOptions<TM> = {}\n): ThreadsAsyncResult<TM, CM> {\n const { scrollOnLoad = true } = options;\n\n const client = useClient();\n const room = useRoom();\n const { store, getOrCreateThreadsPollerForRoomId } = getRoomExtrasForClient<\n TM,\n CM\n >(client);\n const queryKey = makeRoomThreadsQueryKey(room.id, options.query);\n\n const poller = getOrCreateThreadsPollerForRoomId(room.id);\n\n useEffect(\n () =>\n void store.outputs.loadingRoomThreads\n .getOrCreate(queryKey)\n .waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => poller.dec();\n }, [poller]);\n\n const result = useSignal(\n store.outputs.loadingRoomThreads.getOrCreate(queryKey).signal\n );\n\n useScrollToCommentOnLoadEffect(scrollOnLoad, result);\n return result;\n}\n\nfunction useSearchComments<TM extends BaseMetadata>(\n options: UseSearchCommentsOptions<TM>\n): SearchCommentsAsyncResult {\n const [result, setResult] = useState<SearchCommentsAsyncResult>({\n isLoading: true,\n });\n\n const currentRequestInfo = useRef<{\n id: number;\n controller: AbortController;\n } | null>(null);\n\n const timeout = useRef<number | null>(null);\n\n const client = useClient();\n const room = useRoom();\n\n const queryKey = stableStringify([room.id, options.query]);\n\n useEffect(() => {\n const currentRequestId = (currentRequestInfo.current?.id ?? 0) + 1;\n const controller = new AbortController();\n\n currentRequestInfo.current = { id: currentRequestId, controller };\n setResult((result) => {\n if (result.isLoading) return result;\n // **NOTE**: Should we keep the old result but only set loading to true.\n // All our other hooks (useThreads) is defined in the way so that if the result is loading, the result is undefined.\n return { isLoading: true };\n });\n\n timeout.current = window.setTimeout(() => {\n client[kInternal].httpClient\n .searchComments(\n {\n roomId: room.id,\n query: options.query,\n },\n { signal: controller.signal }\n )\n .then(({ data }) => {\n // If the request was aborted, we do not update the result received from this request as it may be stale.\n if (controller.signal.aborted) return;\n\n // If a new request was made while this request was in flight, we do not update the result received from this request as it may be stale.\n if (currentRequestInfo.current?.id !== currentRequestId) return;\n\n setResult({ isLoading: false, results: data });\n\n // Clear the current request info to avoid stale results from the next request.\n currentRequestInfo.current = null;\n })\n .catch((err) => {\n // If the request was aborted, we do not update the result received from this request as it may be stale.\n if (controller.signal.aborted) return;\n\n // If a new request was made while this request was in flight, we do not update the result received from this request as it may be stale.\n if (currentRequestInfo.current?.id !== currentRequestId) return;\n\n setResult({ isLoading: false, error: err as Error });\n\n // Clear the current request info to avoid stale results from the next request.\n currentRequestInfo.current = null;\n });\n }, 300 /* debounce time */);\n\n return () => {\n // If there is a timeout in progress, cancel it before we initiate a new one\n if (timeout.current !== null) {\n window.clearTimeout(timeout.current);\n }\n\n // Cancel any in-flight request and initiate a new request\n if (currentRequestInfo.current !== null) {\n currentRequestInfo.current.controller.abort();\n }\n };\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [queryKey, client, room.id]);\n\n return result;\n}\n\nfunction useCreateThread<TM extends BaseMetadata, CM extends BaseMetadata>(): (\n options: CreateThreadOptions<TM, CM>\n) => ThreadData<TM, CM> {\n return useCreateRoomThread(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useCreateRoomThread<TM extends BaseMetadata, CM extends BaseMetadata>(\n roomId: string\n): (options: CreateThreadOptions<TM, CM>) => ThreadData<TM, CM> {\n const client = useClient();\n\n return useCallback(\n (options: CreateThreadOptions<TM, CM>): ThreadData<TM, CM> => {\n const body = options.body;\n const metadata = options.metadata ?? ({} as TM);\n const commentMetadata = options.commentMetadata ?? ({} as CM);\n const attachments = options.attachments;\n\n const threadId = createThreadId();\n const commentId = createCommentId();\n const createdAt = new Date();\n\n const newComment: CommentData<CM> = {\n id: commentId,\n threadId,\n roomId,\n createdAt,\n type: \"comment\",\n userId: getCurrentUserId(client),\n body,\n reactions: [],\n attachments: attachments ?? [],\n metadata: commentMetadata,\n };\n const newThread: ThreadData<TM, CM> = {\n id: threadId,\n type: \"thread\",\n createdAt,\n updatedAt: createdAt,\n roomId,\n metadata,\n comments: [newComment],\n resolved: false,\n };\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"create-thread\",\n thread: newThread,\n roomId,\n });\n\n const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n client[kInternal].httpClient\n .createThread({\n roomId,\n threadId,\n commentId,\n body,\n metadata,\n commentMetadata,\n attachmentIds,\n })\n .then(\n (thread) => {\n // Replace the optimistic update by the real thing\n store.createThread(optimisticId, thread);\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"CREATE_THREAD_ERROR\",\n roomId,\n threadId,\n commentId,\n body,\n metadata,\n commentMetadata,\n },\n err\n )\n );\n\n return newThread;\n },\n [client, roomId]\n );\n}\n\nfunction useDeleteThread(): (threadId: string) => void {\n return useDeleteRoomThread(useRoom().id);\n}\n\nfunction useDeleteRoomThread(roomId: string): (threadId: string) => void {\n const client = useClient();\n return useCallback(\n (threadId: string): void => {\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n const userId = getCurrentUserId(client);\n\n const existing = store.outputs.threads.get().get(threadId);\n if (existing?.comments?.[0]?.userId !== userId) {\n throw new Error(\"Only the thread creator can delete the thread\");\n }\n\n const optimisticId = store.optimisticUpdates.add({\n type: \"delete-thread\",\n roomId,\n threadId,\n deletedAt: new Date(),\n });\n\n client[kInternal].httpClient.deleteThread({ roomId, threadId }).then(\n () => {\n // Replace the optimistic update by the real thing\n store.deleteThread(threadId, optimisticId);\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n { type: \"DELETE_THREAD_ERROR\", roomId, threadId },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\nfunction useEditThreadMetadata<TM extends BaseMetadata>() {\n return useEditRoomThreadMetadata<TM>(useRoom().id);\n}\n\nfunction useEditRoomThreadMetadata<TM extends BaseMetadata>(roomId: string) {\n const client = useClient();\n return useCallback(\n (options: EditThreadMetadataOptions<TM>): void => {\n if (!options.metadata) {\n return;\n }\n\n const threadId = options.threadId;\n const metadata = options.metadata;\n const updatedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"edit-thread-metadata\",\n metadata,\n threadId,\n updatedAt,\n });\n\n client[kInternal].httpClient\n .editThreadMetadata({ roomId, threadId, metadata })\n .then(\n (metadata) =>\n // Replace the optimistic update by the real thing\n store.patchThread(threadId, optimisticId, { metadata }, updatedAt),\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"EDIT_THREAD_METADATA_ERROR\",\n roomId,\n threadId,\n metadata,\n },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\nfunction useEditCommentMetadata<CM extends BaseMetadata>() {\n return useEditRoomCommentMetadata<CM>(useRoom().id);\n}\n\nfunction useEditRoomCommentMetadata<CM extends BaseMetadata>(roomId: string) {\n const client = useClient();\n return useCallback(\n (options: EditCommentMetadataOptions<CM>): void => {\n if (!options.metadata) {\n return;\n }\n\n const threadId = options.threadId;\n const commentId = options.commentId;\n const metadata = options.metadata;\n const updatedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"edit-comment-metadata\",\n threadId,\n commentId,\n metadata,\n updatedAt,\n });\n\n client[kInternal].httpClient\n .editCommentMetadata({ roomId, threadId, commentId, metadata })\n .then(\n (updatedMetadata) =>\n // Replace the optimistic update by the real thing\n store.editCommentMetadata(\n threadId,\n commentId,\n optimisticId,\n updatedMetadata,\n updatedAt\n ),\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"EDIT_COMMENT_METADATA_ERROR\",\n roomId,\n threadId,\n commentId,\n metadata,\n },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that adds a comment to a thread.\n *\n * @example\n * const createComment = useCreateComment();\n * createComment({ threadId: \"th_xxx\", body: {} });\n */\nfunction useCreateComment<CM extends BaseMetadata>(): (\n options: CreateCommentOptions<CM>\n) => CommentData<CM> {\n return useCreateRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useCreateRoomComment<CM extends BaseMetadata>(\n roomId: string\n): (options: CreateCommentOptions<CM>) => CommentData<CM> {\n const client = useClient();\n return useCallback(\n (options: CreateCommentOptions<CM>): CommentData<CM> => {\n const { threadId, body } = options;\n const metadata = options.metadata ?? ({} as CM);\n const attachments = options.attachments ?? [];\n const commentId = createCommentId();\n const createdAt = new Date();\n\n const comment: CommentData<CM> = {\n id: commentId,\n threadId,\n roomId,\n type: \"comment\",\n createdAt,\n userId: getCurrentUserId(client),\n body,\n reactions: [],\n attachments: attachments ?? [],\n metadata,\n };\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"create-comment\",\n comment,\n });\n\n const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n client[kInternal].httpClient\n .createComment({\n roomId,\n threadId,\n commentId,\n body,\n metadata,\n attachmentIds,\n })\n .then(\n (newComment) => {\n // Replace the optimistic update by the real thing\n store.createComment(newComment, optimisticId);\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"CREATE_COMMENT_ERROR\",\n roomId,\n threadId,\n commentId,\n body,\n metadata,\n },\n err\n )\n );\n\n return comment;\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that edits a comment.\n *\n * @example\n * const editComment = useEditComment()\n * editComment({ threadId: \"th_xxx\", commentId: \"cm_xxx\", body: {} })\n */\nfunction useEditComment<CM extends BaseMetadata>(): (\n options: EditCommentOptions<CM>\n) => void {\n return useEditRoomComment<CM>(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useEditRoomComment<CM extends BaseMetadata>(\n roomId: string\n): (options: EditCommentOptions<CM>) => void {\n const client = useClient();\n return useCallback(\n ({\n threadId,\n commentId,\n body,\n attachments,\n metadata,\n }: EditCommentOptions<CM>): void => {\n const editedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const existing = store.outputs.threads.get().getEvenIfDeleted(threadId);\n\n if (existing === undefined) {\n console.warn(\n `Internal unexpected behavior. Cannot edit comment in thread \"${threadId}\" because the thread does not exist in the cache.`\n );\n return;\n }\n\n const comment = existing.comments.find(\n (comment) => comment.id === commentId\n );\n\n if (comment === undefined || comment.deletedAt !== undefined) {\n console.warn(\n `Internal unexpected behavior. Cannot edit comment \"${commentId}\" in thread \"${threadId}\" because the comment does not exist in the cache.`\n );\n return;\n }\n\n const updatedMetadata =\n metadata !== undefined\n ? {\n ...comment.metadata,\n ...metadata,\n }\n : comment.metadata;\n\n const optimisticId = store.optimisticUpdates.add({\n type: \"edit-comment\",\n comment: {\n ...comment,\n editedAt,\n body,\n attachments: attachments ?? [],\n metadata: updatedMetadata,\n },\n });\n\n const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n client[kInternal].httpClient\n .editComment({\n roomId,\n threadId,\n commentId,\n body,\n attachmentIds,\n metadata,\n })\n .then(\n (editedComment) => {\n // Replace the optimistic update by the real thing\n store.editComment(threadId, optimisticId, editedComment);\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"EDIT_COMMENT_ERROR\",\n roomId,\n threadId,\n commentId,\n body,\n metadata: updatedMetadata,\n },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that deletes a comment.\n * If it is the last non-deleted comment, the thread also gets deleted.\n *\n * @example\n * const deleteComment = useDeleteComment();\n * deleteComment({ threadId: \"th_xxx\", commentId: \"cm_xxx\" })\n */\nfunction useDeleteComment() {\n return useDeleteRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useDeleteRoomComment(roomId: string) {\n const client = useClient();\n\n return useCallback(\n ({ threadId, commentId }: DeleteCommentOptions): void => {\n const deletedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n const optimisticId = store.optimisticUpdates.add({\n type: \"delete-comment\",\n threadId,\n commentId,\n deletedAt,\n roomId,\n });\n\n client[kInternal].httpClient\n .deleteComment({ roomId, threadId, commentId })\n .then(\n () => {\n // Replace the optimistic update by the real thing\n store.deleteComment(threadId, optimisticId, commentId, deletedAt);\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n { type: \"DELETE_COMMENT_ERROR\", roomId, threadId, commentId },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\nfunction useAddReaction() {\n return useAddRoomCommentReaction(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useAddRoomCommentReaction(roomId: string) {\n const client = useClient();\n return useCallback(\n ({ threadId, commentId, emoji }: CommentReactionOptions): void => {\n const createdAt = new Date();\n const userId = getCurrentUserId(client);\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n const optimisticId = store.optimisticUpdates.add({\n type: \"add-reaction\",\n threadId,\n commentId,\n reaction: {\n emoji,\n userId,\n createdAt,\n },\n });\n\n client[kInternal].httpClient\n .addReaction({ roomId, threadId, commentId, emoji })\n .then(\n (addedReaction) => {\n // Replace the optimistic update by the real thing\n store.addReaction(\n threadId,\n optimisticId,\n commentId,\n addedReaction,\n createdAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"ADD_REACTION_ERROR\",\n roomId,\n threadId,\n commentId,\n emoji,\n },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that removes a reaction on a comment.\n *\n * @example\n * const removeReaction = useRemoveReaction();\n * removeReaction({ threadId: \"th_xxx\", commentId: \"cm_xxx\", emoji: \"👍\" })\n */\nfunction useRemoveReaction() {\n return useRemoveRoomCommentReaction(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useRemoveRoomCommentReaction(roomId: string) {\n const client = useClient();\n return useCallback(\n ({ threadId, commentId, emoji }: CommentReactionOptions): void => {\n const userId = getCurrentUserId(client);\n\n const removedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"remove-reaction\",\n threadId,\n commentId,\n emoji,\n userId,\n removedAt,\n });\n\n client[kInternal].httpClient\n .removeReaction({ roomId, threadId, commentId, emoji })\n .then(\n () => {\n // Replace the optimistic update by the real thing\n store.removeReaction(\n threadId,\n optimisticId,\n commentId,\n emoji,\n userId,\n removedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"REMOVE_REACTION_ERROR\",\n roomId,\n threadId,\n commentId,\n emoji,\n },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n/**\n * Returns a function that marks a thread as read.\n *\n * @example\n * const markThreadAsRead = useMarkThreadAsRead();\n * markThreadAsRead(\"th_xxx\");\n */\nfunction useMarkThreadAsRead() {\n return useMarkRoomThreadAsRead(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useMarkRoomThreadAsRead(roomId: string) {\n const client = useClient();\n return useCallback(\n (threadId: string) => {\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const inboxNotification = Object.values(\n store.outputs.notifications.get().notificationsById\n ).find(\n (inboxNotification) =>\n inboxNotification.kind === \"thread\" &&\n inboxNotification.threadId === threadId\n );\n\n if (!inboxNotification) return;\n\n const now = new Date();\n\n const optimisticId = store.optimisticUpdates.add({\n type: \"mark-inbox-notification-as-read\",\n inboxNotificationId: inboxNotification.id,\n readAt: now,\n });\n\n client[kInternal].httpClient\n .markRoomInboxNotificationAsRead({\n roomId,\n inboxNotificationId: inboxNotification.id,\n })\n .then(\n () => {\n // Replace the optimistic update by the real thing\n store.markInboxNotificationRead(\n inboxNotification.id,\n now,\n optimisticId\n );\n },\n (err: Error) => {\n onMutationFailure(\n optimisticId,\n {\n type: \"MARK_INBOX_NOTIFICATION_AS_READ_ERROR\",\n roomId,\n inboxNotificationId: inboxNotification.id,\n },\n err\n );\n return;\n }\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that marks a thread as resolved.\n *\n * @example\n * const markThreadAsResolved = useMarkThreadAsResolved();\n * markThreadAsResolved(\"th_xxx\");\n */\nfunction useMarkThreadAsResolved() {\n return useMarkRoomThreadAsResolved(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useMarkRoomThreadAsResolved(roomId: string) {\n const client = useClient();\n return useCallback(\n (threadId: string) => {\n const updatedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"mark-thread-as-resolved\",\n threadId,\n updatedAt,\n });\n\n client[kInternal].httpClient\n .markThreadAsResolved({ roomId, threadId })\n .then(\n () => {\n // Replace the optimistic update by the real thing\n store.patchThread(\n threadId,\n optimisticId,\n { resolved: true },\n updatedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n { type: \"MARK_THREAD_AS_RESOLVED_ERROR\", roomId, threadId },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that marks a thread as unresolved.\n *\n * @example\n * const markThreadAsUnresolved = useMarkThreadAsUnresolved();\n * markThreadAsUnresolved(\"th_xxx\");\n */\nfunction useMarkThreadAsUnresolved() {\n return useMarkRoomThreadAsUnresolved(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useMarkRoomThreadAsUnresolved(roomId: string) {\n const client = useClient();\n return useCallback(\n (threadId: string) => {\n const updatedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"mark-thread-as-unresolved\",\n threadId,\n updatedAt,\n });\n\n client[kInternal].httpClient\n .markThreadAsUnresolved({ roomId, threadId })\n .then(\n () => {\n // Replace the optimistic update by the real thing\n store.patchThread(\n threadId,\n optimisticId,\n { resolved: false },\n updatedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n { type: \"MARK_THREAD_AS_UNRESOLVED_ERROR\", roomId, threadId },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that subscribes the user to a thread.\n *\n * @example\n * const subscribeToThread = useSubscribeToThread();\n * subscribeToThread(\"th_xxx\");\n */\nfunction useSubscribeToThread() {\n return useSubscribeToRoomThread(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useSubscribeToRoomThread(roomId: string) {\n const client = useClient();\n\n return useCallback(\n (threadId: string) => {\n const subscribedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"subscribe-to-thread\",\n threadId,\n subscribedAt,\n });\n\n client[kInternal].httpClient.subscribeToThread({ roomId, threadId }).then(\n (subscription) => {\n store.createSubscription(subscription, optimisticId);\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n { type: \"SUBSCRIBE_TO_THREAD_ERROR\", roomId, threadId },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that unsubscribes the user from a thread.\n *\n * @example\n * const unsubscribeFromThread = useUnsubscribeFromThread();\n * unsubscribeFromThread(\"th_xxx\");\n */\nfunction useUnsubscribeFromThread() {\n return useUnsubscribeFromRoomThread(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useUnsubscribeFromRoomThread(roomId: string) {\n const client = useClient();\n\n return useCallback(\n (threadId: string) => {\n const unsubscribedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"unsubscribe-from-thread\",\n threadId,\n unsubscribedAt,\n });\n\n client[kInternal].httpClient\n .unsubscribeFromThread({ roomId, threadId })\n .then(\n () => {\n store.deleteSubscription(\n getSubscriptionKey(\"thread\", threadId),\n optimisticId\n );\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n { type: \"UNSUBSCRIBE_FROM_THREAD_ERROR\", roomId, threadId },\n err\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns the subscription status of a thread, methods to update it, and when\n * the thread was last read.\n *\n * @example\n * const { status, subscribe, unsubscribe, unreadSince } = useThreadSubscription(\"th_xxx\");\n */\nfunction useThreadSubscription(threadId: string): ThreadSubscription {\n return useRoomThreadSubscription(useRoom().id, threadId);\n}\n\n/**\n * @private\n */\nfunction useRoomThreadSubscription(\n roomId: string,\n threadId: string\n): ThreadSubscription {\n const client = useClient();\n const { store } = getRoomExtrasForClient(client);\n const subscriptionKey = useMemo(\n () => getSubscriptionKey(\"thread\", threadId),\n [threadId]\n );\n const subscribeToThread = useSubscribeToRoomThread(roomId);\n const unsubscribeFromThread = useUnsubscribeFromRoomThread(roomId);\n const subscribe = useCallback(\n () => subscribeToThread(threadId),\n [subscribeToThread, threadId]\n );\n const unsubscribe = useCallback(\n () => unsubscribeFromThread(threadId),\n [unsubscribeFromThread, threadId]\n );\n\n const signal = store.outputs.threadSubscriptions;\n\n const selector = useCallback(\n (state: SignalType<typeof signal>): ThreadSubscription => {\n const subscription = state.subscriptions[subscriptionKey];\n const notification = state.notifications.find(\n (inboxNotification) =>\n inboxNotification.kind === \"thread\" &&\n inboxNotification.threadId === threadId\n );\n\n if (subscription === undefined) {\n return { status: \"not-subscribed\", subscribe, unsubscribe };\n }\n\n return {\n status: \"subscribed\",\n unreadSince: notification?.readAt ?? null,\n subscribe,\n unsubscribe,\n };\n },\n [subscriptionKey, threadId, subscribe, unsubscribe]\n );\n\n return useSignal(signal, selector, shallow);\n}\n\n/**\n * Returns the user's subscription settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomSubscriptionSettings();\n */\nfunction useRoomSubscriptionSettings(): [\n RoomSubscriptionSettingsAsyncResult,\n (settings: Partial<RoomSubscriptionSettings>) => void,\n] {\n const updateRoomSubscriptionSettings = useUpdateRoomSubscriptionSettings();\n const client = useClient();\n const room = useRoom();\n const { store, getOrCreateSubscriptionSettingsPollerForRoomId } =\n getRoomExtrasForClient(client);\n\n const poller = getOrCreateSubscriptionSettingsPollerForRoomId(room.id);\n\n useEffect(\n () =>\n void store.outputs.roomSubscriptionSettingsByRoomId\n .getOrCreate(room.id)\n .waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => {\n poller.dec();\n };\n }, [poller]);\n\n const settings = useSignal(\n store.outputs.roomSubscriptionSettingsByRoomId.getOrCreate(room.id).signal\n );\n\n return useMemo(() => {\n return [settings, updateRoomSubscriptionSettings];\n }, [settings, updateRoomSubscriptionSettings]);\n}\n\n/**\n * Returns the user's subscription settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomSubscriptionSettings();\n */\nfunction useRoomSubscriptionSettingsSuspense(): [\n RoomSubscriptionSettingsAsyncSuccess,\n (settings: Partial<RoomSubscriptionSettings>) => void,\n] {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const store = getRoomExtrasForClient(client).store;\n const room = useRoom();\n\n // Suspend until there are at least some inbox notifications\n use(\n store.outputs.roomSubscriptionSettingsByRoomId\n .getOrCreate(room.id)\n .waitUntilLoaded()\n );\n\n // We're in a Suspense world here, and as such, the useRoomSubscriptionSettings()\n // hook is expected to only return success results when we're here.\n const [settings, updateRoomSubscriptionSettings] =\n useRoomSubscriptionSettings();\n assert(!settings.error, \"Did not expect error\");\n assert(!settings.isLoading, \"Did not expect loading\");\n\n return useMemo(() => {\n return [settings, updateRoomSubscriptionSettings];\n }, [settings, updateRoomSubscriptionSettings]);\n}\n\n/**\n * Returns the version data bianry for a given version\n *\n * @example\n * const {data} = useHistoryVersionData(versionId);\n */\nfunction useHistoryVersionData(\n versionId: string\n): HistoryVersionDataAsyncResult {\n const [state, setState] = useState<HistoryVersionDataAsyncResult>({\n isLoading: true,\n });\n const room = useRoom();\n useEffect(() => {\n setState({ isLoading: true });\n const load = async () => {\n try {\n const response = await room[kInternal].getTextVersion(versionId);\n const buffer = await response.arrayBuffer();\n const data = new Uint8Array(buffer);\n setState({\n isLoading: false,\n data,\n });\n } catch (error) {\n setState({\n isLoading: false,\n error:\n error instanceof Error\n ? error\n : new Error(\n \"An unknown error occurred while loading this version\"\n ),\n });\n }\n };\n void load();\n }, [room, versionId]);\n return state;\n}\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions, error, isLoading } = useHistoryVersions();\n */\nfunction useHistoryVersions(): HistoryVersionsAsyncResult {\n const client = useClient();\n const room = useRoom();\n\n const { store, getOrCreateVersionsPollerForRoomId } =\n getRoomExtrasForClient(client);\n\n const poller = getOrCreateVersionsPollerForRoomId(room.id);\n\n useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => poller.dec();\n }, [poller]);\n\n useEffect(\n () =>\n void store.outputs.versionsByRoomId.getOrCreate(room.id).waitUntilLoaded()\n\n // NOTE: Deliberately *not* using a dependency array here!\n //\n // It is important to call waitUntil on *every* render.\n // This is harmless though, on most renders, except:\n // 1. The very first render, in which case we'll want to trigger the initial page fetch.\n // 2. All other subsequent renders now \"just\" return the same promise (a quick operation).\n // 3. If ever the promise would fail, then after 5 seconds it would reset, and on the very\n // *next* render after that, a *new* fetch/promise will get created.\n );\n\n return useSignal(store.outputs.versionsByRoomId.getOrCreate(room.id).signal);\n}\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions } = useHistoryVersions();\n */\nfunction useHistoryVersionsSuspense(): HistoryVersionsAsyncSuccess {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const room = useRoom();\n const store = getRoomExtrasForClient(client).store;\n\n use(store.outputs.versionsByRoomId.getOrCreate(room.id).waitUntilLoaded());\n\n const result = useHistoryVersions();\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\n/**\n * Returns a function that updates the user's subscription settings\n * for the current room.\n *\n * @example\n * const updateRoomSubscriptionSettings = useUpdateRoomSubscriptionSettings();\n * updateRoomSubscriptionSettings({ threads: \"all\" });\n */\nfunction useUpdateRoomSubscriptionSettings() {\n const client = useClient();\n const room = useRoom();\n return useCallback(\n (settings: Partial<RoomSubscriptionSettings>) => {\n const { store, onMutationFailure, pollThreadsForRoomId } =\n getRoomExtrasForClient(client);\n const userId = getCurrentUserId(client);\n const optimisticId = store.optimisticUpdates.add({\n type: \"update-room-subscription-settings\",\n roomId: room.id,\n userId,\n settings,\n });\n\n room.updateSubscriptionSettings(settings).then(\n (udpatedSettings) => {\n // Replace the optimistic update by the real thing\n store.updateRoomSubscriptionSettings(\n room.id,\n optimisticId,\n udpatedSettings\n );\n\n // If the `threads` settings are changed, trigger a polling to update thread subscriptions\n if (settings.threads) {\n pollThreadsForRoomId(room.id);\n }\n },\n (err: Error) =>\n onMutationFailure(\n optimisticId,\n {\n type: \"UPDATE_ROOM_SUBSCRIPTION_SETTINGS_ERROR\",\n roomId: room.id,\n },\n err\n )\n );\n },\n [client, room]\n );\n}\n\nfunction useSuspendUntilPresenceReady(): void {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const room = useRoom();\n use(room.waitUntilPresenceReady());\n}\n\nfunction useSelfSuspense<P extends JsonObject, U extends BaseUserMeta>(): User<\n P,\n U\n>;\nfunction useSelfSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n selector: (me: User<P, U>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction useSelfSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n selector?: (me: User<P, U>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T | User<P, U> {\n useSuspendUntilPresenceReady();\n return useSelf(\n selector as (me: User<P, U>) => T,\n isEqual as (prev: T | null, curr: T | null) => boolean\n ) as T | User<P, U>;\n}\n\nfunction useOthersSuspense<\n P extends JsonObject,\n U extends BaseUserMeta,\n>(): readonly User<P, U>[];\nfunction useOthersSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n selector: (others: readonly User<P, U>[]) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction useOthersSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n selector?: (others: readonly User<P, U>[]) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T | readonly User<P, U>[] {\n useSuspendUntilPresenceReady();\n return useOthers(\n selector as (others: readonly User<P, U>[]) => T,\n isEqual as (prev: T, curr: T) => boolean\n ) as T | readonly User<P, U>[];\n}\n\n/**\n * Returns an array of connection IDs. This matches the values you'll get by\n * using the `useOthers()` hook.\n *\n * Roughly equivalent to:\n * useOthers((others) => others.map(other => other.connectionId), shallow)\n *\n * This is useful in particular to implement efficiently rendering components\n * for each user in the room, e.g. cursors.\n *\n * @example\n * const ids = useOthersConnectionIds();\n * // [2, 4, 7]\n */\nfunction useOthersConnectionIdsSuspense(): readonly number[] {\n useSuspendUntilPresenceReady();\n return useOthersConnectionIds();\n}\n\nfunction useOthersMappedSuspense<\n P extends JsonObject,\n U extends BaseUserMeta,\n T,\n>(\n itemSelector: (other: User<P, U>) => T,\n itemIsEqual?: (prev: T, curr: T) => boolean\n): ReadonlyArray<readonly [connectionId: number, data: T]> {\n useSuspendUntilPresenceReady();\n return useOthersMapped(itemSelector, itemIsEqual);\n}\n\nfunction useOtherSuspense<P extends JsonObject, U extends BaseUserMeta, T>(\n connectionId: number,\n selector: (other: User<P, U>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T {\n useSuspendUntilPresenceReady();\n return useOther(connectionId, selector, isEqual);\n}\n\nfunction useSuspendUntilStorageReady(): void {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const room = useRoom();\n use(room.waitUntilStorageReady());\n}\n\nfunction useStorageSuspense<S extends LsonObject, T>(\n selector: (root: ToImmutable<S>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T {\n useSuspendUntilStorageReady();\n return useStorage(\n selector,\n isEqual as (prev: T | null, curr: T | null) => boolean\n ) as T;\n}\n\nfunction useThreadsSuspense<TM extends BaseMetadata, CM extends BaseMetadata>(\n options: UseThreadsOptions<TM> = {}\n): ThreadsAsyncSuccess<TM, CM> {\n // Throw error if we're calling this hook server side\n ensureNotServerSide();\n\n const client = useClient();\n const room = useRoom();\n\n const { store } = getRoomExtrasForClient<TM, CM>(client);\n const queryKey = makeRoomThreadsQueryKey(room.id, options.query);\n\n use(store.outputs.loadingRoomThreads.getOrCreate(queryKey).waitUntilLoaded());\n\n const result = useThreads<TM, CM>(options);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\nfunction selectorFor_useAttachmentUrl(\n state: AsyncResult<string | undefined> | undefined\n): AttachmentUrlAsyncResult {\n if (state === undefined || state?.isLoading) {\n return state ?? { isLoading: true };\n }\n\n if (state.error) {\n return state;\n }\n\n // For now `useAttachmentUrl` doesn't support a custom resolver so this case\n // will never happen as `getAttachmentUrl` will either return a URL or throw.\n // But we might decide to offer a custom resolver in the future to allow\n // self-hosting attachments.\n assert(state.data !== undefined, \"Unexpected missing attachment URL\");\n\n return {\n isLoading: false,\n url: state.data,\n };\n}\n\n/**\n * Returns a presigned URL for an attachment by its ID.\n *\n * @example\n * const { url, error, isLoading } = useAttachmentUrl(\"at_xxx\");\n */\nfunction useAttachmentUrl(attachmentId: string): AttachmentUrlAsyncResult {\n const room = useRoom();\n return useRoomAttachmentUrl(attachmentId, room.id);\n}\n\n/**\n * @private For internal use only. Do not rely on this hook. Use `useAttachmentUrl` instead.\n */\nfunction useRoomAttachmentUrl(\n attachmentId: string,\n roomId: string\n): AttachmentUrlAsyncResult {\n const client = useClient();\n const store =\n client[kInternal].httpClient.getOrCreateAttachmentUrlsStore(roomId);\n\n const getAttachmentUrlState = useCallback(\n () => store.getItemState(attachmentId),\n [store, attachmentId]\n );\n\n useEffect(() => {\n void store.enqueue(attachmentId);\n }, [store, attachmentId]);\n\n return useSyncExternalStoreWithSelector(\n store.subscribe,\n getAttachmentUrlState,\n getAttachmentUrlState,\n selectorFor_useAttachmentUrl,\n shallow\n );\n}\n\n/**\n * Returns a presigned URL for an attachment by its ID.\n *\n * @example\n * const { url } = useAttachmentUrl(\"at_xxx\");\n */\nfunction useAttachmentUrlSuspense(attachmentId: string) {\n const room = useRoom();\n const { attachmentUrlsStore } = room[kInternal];\n\n const getAttachmentUrlState = useCallback(\n () => attachmentUrlsStore.getItemState(attachmentId),\n [attachmentUrlsStore, attachmentId]\n );\n const attachmentUrlState = getAttachmentUrlState();\n\n if (!attachmentUrlState || attachmentUrlState.isLoading) {\n throw attachmentUrlsStore.enqueue(attachmentId);\n }\n\n if (attachmentUrlState.error) {\n throw attachmentUrlState.error;\n }\n\n const state = useSyncExternalStore(\n attachmentUrlsStore.subscribe,\n getAttachmentUrlState,\n getAttachmentUrlState\n );\n assert(state !== undefined, \"Unexpected missing state\");\n assert(!state.isLoading, \"Unexpected loading state\");\n assert(!state.error, \"Unexpected error state\");\n return {\n isLoading: false,\n url: state.data,\n error: undefined,\n } as const;\n}\n\n/**\n * @private For internal use only. Do not rely on this hook.\n */\nfunction useRoomPermissions(roomId: string) {\n const client = useClient();\n const store = getRoomExtrasForClient(client).store;\n return useSignal(store.permissionHints.getPermissionForRoomΣ(roomId));\n}\n\n/**\n * Creates a RoomProvider and a set of typed hooks to use in your app. Note\n * that any RoomProvider created in this way does not need to be nested in\n * LiveblocksProvider, as it already has access to the client.\n */\nexport function createRoomContext<\n P extends JsonObject = DP,\n S extends LsonObject = DS,\n U extends BaseUserMeta = DU,\n E extends Json = DE,\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n>(client: OpaqueClient): RoomContextBundle<P, S, U, E, TM, CM> {\n return getOrCreateRoomContextBundle<P, S, U, E, TM, CM>(client);\n}\n\ntype TypedBundle = RoomContextBundle<DP, DS, DU, DE, DTM, DCM>;\n\n/**\n * Makes a Room available in the component hierarchy below.\n * Joins the room when the component is mounted, and automatically leaves\n * the room when the component is unmounted.\n */\nconst _RoomProvider: TypedBundle[\"RoomProvider\"] = RoomProvider;\n\n/**\n * Returns a callback that lets you broadcast custom events to other users in the room\n *\n * @example\n * const broadcast = useBroadcastEvent();\n *\n * broadcast({ type: \"CUSTOM_EVENT\", data: { x: 0, y: 0 } });\n */\nconst _useBroadcastEvent: TypedBundle[\"useBroadcastEvent\"] = useBroadcastEvent;\n\n/**\n * Get informed when users enter or leave the room, as an event.\n *\n * @example\n * useOthersListener({ type, user, others }) => {\n * if (type === 'enter') {\n * // `user` has joined the room\n * } else if (type === 'leave') {\n * // `user` has left the room\n * }\n * })\n */\nconst _useOthersListener: TypedBundle[\"useOthersListener\"] = useOthersListener;\n\n/**\n * Returns the Room of the nearest RoomProvider above in the React component\n * tree.\n */\nconst _useRoom: TypedBundle[\"useRoom\"] = useRoom;\n\n/**\n * Returns whether the hook is called within a RoomProvider context.\n *\n * @example\n * const isInsideRoom = useIsInsideRoom();\n */\nconst _useIsInsideRoom: TypedBundle[\"useIsInsideRoom\"] = useIsInsideRoom;\n\n/**\n * Returns a function that adds a reaction from a comment.\n *\n * @example\n * const addReaction = useAddReaction();\n * addReaction({ threadId: \"th_xxx\", commentId: \"cm_xxx\", emoji: \"👍\" })\n */\nconst _useAddReaction: TypedBundle[\"useAddReaction\"] = useAddReaction;\n\n/**\n * Create a callback function that lets you mutate Liveblocks state.\n *\n * The first argument that gets passed into your callback will be\n * a \"mutation context\", which exposes the following:\n *\n * - `storage` - The mutable Storage root.\n * You can mutate any Live structures with this, for example:\n * `storage.get('layers').get('layer1').set('fill', 'red')`\n *\n * - `setMyPresence` - Call this with a new (partial) Presence value.\n *\n * - `self` - A read-only version of the latest self, if you need it to\n * compute the next state.\n *\n * - `others` - A read-only version of the latest others list, if you\n * need it to compute the next state.\n *\n * useMutation is like React's useCallback, except that the first argument\n * that gets passed into your callback will be a \"mutation context\".\n *\n * If you want get access to the immutable root somewhere in your mutation,\n * you can use `storage.ToImmutable()`.\n *\n * @example\n * const fillLayers = useMutation(\n * ({ storage }, color: Color) => {\n * ...\n * },\n * [],\n * );\n *\n * fillLayers('red');\n *\n * const deleteLayers = useMutation(\n * ({ storage }) => {\n * ...\n * },\n * [],\n * );\n *\n * deleteLayers();\n */\nconst _useMutation: TypedBundle[\"useMutation\"] = useMutation;\n\n/**\n * Returns a function that creates a thread with an initial comment, and optionally some metadata.\n *\n * @example\n * const createThread = useCreateThread();\n * createThread({ body: {}, metadata: {} });\n */\nconst _useCreateThread: TypedBundle[\"useCreateThread\"] = useCreateThread;\n\n/**\n * Returns a function that deletes a thread and its associated comments.\n * Only the thread creator can delete a thread, it will throw otherwise.\n *\n * @example\n * const deleteThread = useDeleteThread();\n * deleteThread(\"th_xxx\");\n */\nconst _useDeleteThread: TypedBundle[\"useDeleteThread\"] = useDeleteThread;\n\n/**\n * Returns a function that edits a thread's metadata.\n * To delete an existing metadata property, set its value to `null`.\n *\n * @example\n * const editThreadMetadata = useEditThreadMetadata();\n * editThreadMetadata({ threadId: \"th_xxx\", metadata: {} })\n */\nconst _useEditThreadMetadata: TypedBundle[\"useEditThreadMetadata\"] =\n useEditThreadMetadata;\n\n/**\n * Returns a function that adds a comment to a thread.\n *\n * @example\n * const createComment = useCreateComment();\n * createComment({ threadId: \"th_xxx\", body: {} });\n */\nconst _useCreateComment: TypedBundle[\"useCreateComment\"] = useCreateComment;\n\n/**\n * Returns a function that edits a comment.\n *\n * @example\n * const editComment = useEditComment()\n * editComment({ threadId: \"th_xxx\", commentId: \"cm_xxx\", body: {} })\n */\nconst _useEditComment: TypedBundle[\"useEditComment\"] = useEditComment;\n\n/**\n * Returns a function that edits a comment's metadata.\n * To delete an existing metadata property, set its value to `null`.\n *\n * @example\n * const editCommentMetadata = useEditCommentMetadata();\n * editCommentMetadata({ threadId: \"th_xxx\", commentId: \"cm_xxx\", metadata: { tag: \"important\", externalId: 1234 } })\n */\nconst _useEditCommentMetadata: TypedBundle[\"useEditCommentMetadata\"] =\n useEditCommentMetadata;\n\n/**\n * useEventListener is a React hook that allows you to respond to events broadcast\n * by other users in the room.\n *\n * The `user` argument will indicate which `User` instance sent the message.\n * This will be equal to one of the others in the room, but it can be `null`\n * in case this event was broadcasted from the server.\n *\n * @example\n * useEventListener(({ event, user, connectionId }) => {\n * // ^^^^ Will be Client A\n * if (event.type === \"CUSTOM_EVENT\") {\n * // Do something\n * }\n * });\n */\nconst _useEventListener: TypedBundle[\"useEventListener\"] = useEventListener;\n\n/**\n * Returns the presence of the current user of the current room, and a function to update it.\n * It is different from the setState function returned by the useState hook from\n * You don't need to pass the full presence object to update it.\n *\n * @example\n * const [myPresence, updateMyPresence] = useMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, \"myPresence\" will be equal to \"{ x: 0, y: 0 }\"\n */\nconst _useMyPresence: TypedBundle[\"useMyPresence\"] = useMyPresence;\n\n/**\n * Related to useOthers(), but optimized for selecting only \"subsets\" of\n * others. This is useful for performance reasons in particular, because\n * selecting only a subset of users also means limiting the number of\n * re-renders that will be triggered.\n *\n * @example\n * const avatars = useOthersMapped(user => user.info.avatar);\n * // ^^^^^^^\n * // { connectionId: number; data: string }[]\n *\n * The selector function you pass to useOthersMapped() is called an \"item\n * selector\", and operates on a single user at a time. If you provide an\n * (optional) \"item comparison\" function, it will be used to compare each\n * item pairwise.\n *\n * For example, to select multiple properties:\n *\n * @example\n * const avatarsAndCursors = useOthersMapped(\n * user => [u.info.avatar, u.presence.cursor],\n * shallow, // 👈\n * );\n */\nconst _useOthersMapped: TypedBundle[\"useOthersMapped\"] = useOthersMapped;\n\n/**\n * Related to useOthers(), but optimized for selecting only \"subsets\" of\n * others. This is useful for performance reasons in particular, because\n * selecting only a subset of users also means limiting the number of\n * re-renders that will be triggered.\n *\n * @example\n * const avatars = useOthersMapped(user => user.info.avatar);\n * // ^^^^^^^\n * // { connectionId: number; data: string }[]\n *\n * The selector function you pass to useOthersMapped() is called an \"item\n * selector\", and operates on a single user at a time. If you provide an\n * (optional) \"item comparison\" function, it will be used to compare each\n * item pairwise.\n *\n * For example, to select multiple properties:\n *\n * @example\n * const avatarsAndCursors = useOthersMapped(\n * user => [u.info.avatar, u.presence.cursor],\n * shallow, // 👈\n * );\n */\nconst _useOthersMappedSuspense: TypedBundle[\"suspense\"][\"useOthersMapped\"] =\n useOthersMappedSuspense;\n\n/**\n * Returns the threads within the current room.\n *\n * @example\n * const { threads, error, isLoading } = useThreads();\n */\nconst _useThreads: TypedBundle[\"useThreads\"] = useThreads;\n\n/**\n * Returns the result of searching comments by text in the current room. The result includes the id and the plain text content of the matched comments along with the parent thread id of the comment.\n *\n * @example\n * const { results, error, isLoading } = useSearchComments({ query: { text: \"hello\"} });\n */\nconst _useSearchComments: TypedBundle[\"useSearchComments\"] = useSearchComments;\n\n/**\n * Returns the threads within the current room.\n *\n * @example\n * const { threads } = useThreads();\n */\nconst _useThreadsSuspense: TypedBundle[\"suspense\"][\"useThreads\"] =\n useThreadsSuspense;\n\n/**\n * Returns the user's subscription settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomSubscriptionSettings();\n */\nconst _useRoomSubscriptionSettings: TypedBundle[\"useRoomSubscriptionSettings\"] =\n useRoomSubscriptionSettings;\n\n/**\n * Returns the user's subscription settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomSubscriptionSettings();\n */\nconst _useRoomSubscriptionSettingsSuspense: TypedBundle[\"suspense\"][\"useRoomSubscriptionSettings\"] =\n useRoomSubscriptionSettingsSuspense;\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions, error, isLoading } = useHistoryVersions();\n */\nconst _useHistoryVersions: TypedBundle[\"useHistoryVersions\"] =\n useHistoryVersions;\n\n/**\n * (Private beta) Returns a history of versions of the current room.\n *\n * @example\n * const { versions } = useHistoryVersions();\n */\nconst _useHistoryVersionsSuspense: TypedBundle[\"suspense\"][\"useHistoryVersions\"] =\n useHistoryVersionsSuspense;\n\n/**\n * Given a connection ID (as obtained by using `useOthersConnectionIds`), you\n * can call this selector deep down in your component stack to only have the\n * component re-render if properties for this particular user change.\n *\n * @example\n * // Returns only the selected values re-renders whenever that selection changes)\n * const { x, y } = useOther(2, user => user.presence.cursor);\n */\nconst _useOther: TypedBundle[\"useOther\"] = useOther;\n\n/**\n * Returns an array with information about all the users currently connected in\n * the room (except yourself).\n *\n * @example\n * const others = useOthers();\n *\n * // Example to map all cursors in JSX\n * return (\n * <>\n * {others.map((user) => {\n * if (user.presence.cursor == null) {\n * return null;\n * }\n * return <Cursor key={user.connectionId} cursor={user.presence.cursor} />\n * })}\n * </>\n * )\n */\nfunction _useOthers(): readonly User<DP, DU>[];\n/**\n * Extract arbitrary data based on all the users currently connected in the\n * room (except yourself).\n *\n * The selector function will get re-evaluated any time a user enters or\n * leaves the room, as well as whenever their presence data changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useOthers()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n *\n * @example\n * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow);\n * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow);\n * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping));\n *\n */\nfunction _useOthers<T>(\n selector: (others: readonly User<DP, DU>[]) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction _useOthers(...args: any[]) {\n return useOthers(...(args as []));\n}\n\n/**\n * Given a connection ID (as obtained by using `useOthersConnectionIds`), you\n * can call this selector deep down in your component stack to only have the\n * component re-render if properties for this particular user change.\n *\n * @example\n * // Returns only the selected values re-renders whenever that selection changes)\n * const { x, y } = useOther(2, user => user.presence.cursor);\n */\nconst _useOtherSuspense: TypedBundle[\"suspense\"][\"useOther\"] = useOtherSuspense;\n\n/**\n * Returns an array with information about all the users currently connected in\n * the room (except yourself).\n *\n * @example\n * const others = useOthers();\n *\n * // Example to map all cursors in JSX\n * return (\n * <>\n * {others.map((user) => {\n * if (user.presence.cursor == null) {\n * return null;\n * }\n * return <Cursor key={user.connectionId} cursor={user.presence.cursor} />\n * })}\n * </>\n * )\n */\nfunction _useOthersSuspense(): readonly User<DP, DU>[];\n/**\n * Extract arbitrary data based on all the users currently connected in the\n * room (except yourself).\n *\n * The selector function will get re-evaluated any time a user enters or\n * leaves the room, as well as whenever their presence data changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useOthers()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n *\n * @example\n * const avatars = useOthers(users => users.map(u => u.info.avatar), shallow);\n * const cursors = useOthers(users => users.map(u => u.presence.cursor), shallow);\n * const someoneIsTyping = useOthers(users => users.some(u => u.presence.isTyping));\n *\n */\nfunction _useOthersSuspense<T>(\n selector: (others: readonly User<DP, DU>[]) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction _useOthersSuspense(...args: any[]) {\n return useOthersSuspense(...(args as []));\n}\n\n/**\n * Extract arbitrary data from the Liveblocks Storage state, using an\n * arbitrary selector function.\n *\n * The selector function will get re-evaluated any time something changes in\n * Storage. The value returned by your selector function will also be the\n * value returned by the hook.\n *\n * The `root` value that gets passed to your selector function is\n * a immutable/readonly version of your Liveblocks storage root.\n *\n * The component that uses this hook will automatically re-render if the\n * returned value changes.\n *\n * By default `useStorage()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n */\nconst _useStorage: TypedBundle[\"useStorage\"] = useStorage;\n\n/**\n * Extract arbitrary data from the Liveblocks Storage state, using an\n * arbitrary selector function.\n *\n * The selector function will get re-evaluated any time something changes in\n * Storage. The value returned by your selector function will also be the\n * value returned by the hook.\n *\n * The `root` value that gets passed to your selector function is\n * a immutable/readonly version of your Liveblocks storage root.\n *\n * The component that uses this hook will automatically re-render if the\n * returned value changes.\n *\n * By default `useStorage()` uses strict `===` to check for equality. Take\n * extra care when returning a computed object or list, for example when you\n * return the result of a .map() or .filter() call from the selector. In\n * those cases, you'll probably want to use a `shallow` comparison check.\n */\nconst _useStorageSuspense: TypedBundle[\"suspense\"][\"useStorage\"] =\n useStorageSuspense;\n\n/**\n * Gets the current user once it is connected to the room.\n *\n * @example\n * const me = useSelf();\n * if (me !== null) {\n * const { x, y } = me.presence.cursor;\n * }\n */\nfunction _useSelf(): User<DP, DU> | null;\n/**\n * Extract arbitrary data based on the current user.\n *\n * The selector function will get re-evaluated any time your presence data\n * changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useSelf()` uses strict `===` to check for equality. Take extra\n * care when returning a computed object or list, for example when you return\n * the result of a .map() or .filter() call from the selector. In those\n * cases, you'll probably want to use a `shallow` comparison check.\n *\n * Will return `null` while Liveblocks isn't connected to a room yet.\n *\n * @example\n * const cursor = useSelf(me => me.presence.cursor);\n * if (cursor !== null) {\n * const { x, y } = cursor;\n * }\n *\n */\nfunction _useSelf<T>(\n selector: (me: User<DP, DU>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T | null;\nfunction _useSelf(...args: any[]) {\n return useSelf(...(args as []));\n}\n\n/**\n * Gets the current user once it is connected to the room.\n *\n * @example\n * const me = useSelf();\n * const { x, y } = me.presence.cursor;\n */\nfunction _useSelfSuspense(): User<DP, DU>;\n/**\n * Extract arbitrary data based on the current user.\n *\n * The selector function will get re-evaluated any time your presence data\n * changes.\n *\n * The component that uses this hook will automatically re-render if your\n * selector function returns a different value from its previous run.\n *\n * By default `useSelf()` uses strict `===` to check for equality. Take extra\n * care when returning a computed object or list, for example when you return\n * the result of a .map() or .filter() call from the selector. In those\n * cases, you'll probably want to use a `shallow` comparison check.\n *\n * @example\n * const cursor = useSelf(me => me.presence.cursor);\n * const { x, y } = cursor;\n *\n */\nfunction _useSelfSuspense<T>(\n selector: (me: User<DP, DU>) => T,\n isEqual?: (prev: T, curr: T) => boolean\n): T;\nfunction _useSelfSuspense(...args: any[]) {\n return useSelfSuspense(...(args as []));\n}\n\n/**\n * Returns the mutable (!) Storage root. This hook exists for\n * backward-compatible reasons.\n *\n * @example\n * const [root] = useStorageRoot();\n */\nconst _useStorageRoot: TypedBundle[\"useStorageRoot\"] = useStorageRoot;\n\n/**\n * useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.\n * If you don't use the current user presence in your component, but you need to update it (e.g. live cursor), it's better to use useUpdateMyPresence to avoid unnecessary renders.\n *\n * @example\n * const updateMyPresence = useUpdateMyPresence();\n * updateMyPresence({ x: 0 });\n * updateMyPresence({ y: 0 });\n *\n * // At the next render, the presence of the current user will be equal to \"{ x: 0, y: 0 }\"\n */\nconst _useUpdateMyPresence: TypedBundle[\"useUpdateMyPresence\"] =\n useUpdateMyPresence;\n\nexport {\n _RoomProvider as RoomProvider,\n _useAddReaction as useAddReaction,\n useAddRoomCommentReaction,\n useAttachmentUrl,\n useAttachmentUrlSuspense,\n _useBroadcastEvent as useBroadcastEvent,\n useCanRedo,\n useCanUndo,\n _useCreateComment as useCreateComment,\n useCreateRoomComment,\n useCreateRoomThread,\n useCreateTextMention,\n _useCreateThread as useCreateThread,\n useDeleteComment,\n useDeleteRoomComment,\n useDeleteRoomThread,\n useDeleteTextMention,\n _useDeleteThread as useDeleteThread,\n _useEditComment as useEditComment,\n _useEditCommentMetadata as useEditCommentMetadata,\n useEditRoomComment,\n useEditRoomCommentMetadata,\n useEditRoomThreadMetadata,\n _useEditThreadMetadata as useEditThreadMetadata,\n _useEventListener as useEventListener,\n useHistory,\n useHistoryVersionData,\n _useHistoryVersions as useHistoryVersions,\n _useHistoryVersionsSuspense as useHistoryVersionsSuspense,\n _useIsInsideRoom as useIsInsideRoom,\n useLostConnectionListener,\n useMarkRoomThreadAsRead,\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\n useMarkThreadAsRead,\n useMarkThreadAsResolved,\n useMarkThreadAsUnresolved,\n useMentionSuggestionsCache,\n _useMutation as useMutation,\n _useMyPresence as useMyPresence,\n _useOther as useOther,\n _useOthers as useOthers,\n useOthersConnectionIds,\n useOthersConnectionIdsSuspense,\n _useOthersListener as useOthersListener,\n _useOthersMapped as useOthersMapped,\n _useOthersMappedSuspense as useOthersMappedSuspense,\n _useOthersSuspense as useOthersSuspense,\n _useOtherSuspense as useOtherSuspense,\n useRedo,\n useRemoveReaction,\n useRemoveRoomCommentReaction,\n useReportTextEditor,\n useResolveMentionSuggestions,\n _useRoom as useRoom,\n useRoomAttachmentUrl,\n useRoomPermissions,\n _useRoomSubscriptionSettings as useRoomSubscriptionSettings,\n _useRoomSubscriptionSettingsSuspense as useRoomSubscriptionSettingsSuspense,\n useRoomThreadSubscription,\n _useSearchComments as useSearchComments,\n _useSelf as useSelf,\n _useSelfSuspense as useSelfSuspense,\n useStatus,\n _useStorage as useStorage,\n _useStorageRoot as useStorageRoot,\n _useStorageSuspense as useStorageSuspense,\n useSubscribeToRoomThread,\n useSubscribeToThread,\n _useThreads as useThreads,\n _useThreadsSuspense as useThreadsSuspense,\n useThreadSubscription,\n useUndo,\n useUnsubscribeFromRoomThread,\n useUnsubscribeFromThread,\n _useUpdateMyPresence as useUpdateMyPresence,\n useUpdateRoomSubscriptionSettings,\n useYjsProvider,\n};\n","import type { BaseMetadata } from \"@liveblocks/client\";\nimport { useEffect } from \"react\";\n\nimport type { ThreadsAsyncResult } from \"./types\";\n\nfunction handleScrollToCommentOnLoad(\n shouldScrollOnLoad: boolean,\n state: ThreadsAsyncResult<BaseMetadata, BaseMetadata>\n) {\n if (shouldScrollOnLoad === false) return;\n\n if (!state.threads) return;\n\n const isWindowDefined = typeof window !== \"undefined\";\n if (!isWindowDefined) return;\n\n const hash = window.location.hash;\n const commentId = hash.slice(1);\n\n // If the hash is not a comment ID, we do not scroll to it\n if (!commentId.startsWith(\"cm_\")) return;\n\n // If a comment with the ID does not exist in the DOM, we do not scroll to it\n const comment = document.getElementById(commentId);\n if (comment === null) return;\n\n const comments = state.threads.flatMap((thread) => thread.comments);\n const isCommentInThreads = comments.some(\n (comment) => comment.id === commentId\n );\n\n // If the comment is not in the threads for this hook, we do not scroll to it\n if (!isCommentInThreads) return;\n\n comment.scrollIntoView();\n}\n\n/**\n * Scroll to the comment with the ID in the hash of the URL based on whether\n * the query is loading and whether the hook should scroll to the comment on load.\n */\nexport function useScrollToCommentOnLoadEffect(\n shouldScrollOnLoad: boolean,\n state: ThreadsAsyncResult<BaseMetadata, BaseMetadata>\n) {\n useEffect(\n () => {\n handleScrollToCommentOnLoad(shouldScrollOnLoad, state);\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps -- We only want to run this effect once\n [state.isLoading]\n );\n}\n"],"mappings":"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","names":["useEffect","RegisterAiKnowledge","useEffect","layerKey","RegisterAiTool","useEffect","useRef","nextSelection","console","DefaultMap","kInternal","raise","shallow","useCallback","useEffect","useMemo","useState","useSyncExternalStore","useMemo","useMemo","batch","getSubscriptionKey","kInternal","MutableSignal","nanoid","MutableSignal","MutableSignal","autoRetry","MutableSignal","getSubscriptionKey","updates","batch","kInternal","nanoid","threads","existingComment","existingReaction","identity","useEffect","kInternal","console","DefaultMap","useInboxNotificationThread","useMarkInboxNotificationAsRead","useMarkAllInboxNotificationsAsRead","useDeleteInboxNotification","useDeleteAllInboxNotifications","useUpdateNotificationSettings","LiveblocksProvider","shallow","useCallback","raise","settings","useMemo","useSyncExternalStore","useClient","useSyncStatus","useState","shallow","assert","console","DefaultMap","getSubscriptionKey","HttpError","kInternal","makePoller","stableStringify","useCallback","useEffect","useMemo","useRef","useState","useSyncExternalStore","useEffect","comment","jsx","noop","identity","kInternal","_extras","_bundles","HttpError","console","DefaultMap","makePoller","useState","useCallback","useEffect","room","useSyncExternalStore","useRef","shallow","other","rootOrNull","useMemo","stableStringify","result","metadata","comment","inboxNotification","getSubscriptionKey","assert"]}
|