@liveblocks/react 2.13.3-emails1 → 2.14.0-v2encoding

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/contexts.ts","../src/liveblocks.tsx","../src/config.ts","../src/lib/shallow2.ts","../src/lib/use-initial.ts","../src/lib/use-latest.ts","../src/lib/use-polyfill.ts","../src/umbrella-store.ts","../src/lib/autobind.ts","../src/ThreadDB.ts","../src/lib/guards.ts","../src/lib/querying.ts","../src/types/errors.ts","../src/room.tsx","../src/use-scroll-to-comment-on-load-effect.ts"],"sourcesContent":["import type {\n BaseMetadata,\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport type { OpaqueRoom } from \"@liveblocks/core\";\nimport * as React from \"react\";\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 = React.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 M extends BaseMetadata,\n>(): Room<P, S, U, E, M> | null {\n return React.useContext(RoomContext) as Room<P, S, U, E, M> | 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 {\n BaseMetadata,\n BaseUserMeta,\n Client,\n ClientOptions,\n ThreadData,\n} from \"@liveblocks/client\";\nimport type {\n AsyncResult,\n BaseRoomInfo,\n DM,\n DU,\n InboxNotificationData,\n OpaqueClient,\n SyncStatus,\n} from \"@liveblocks/core\";\nimport {\n assert,\n createClient,\n kInternal,\n makePoller,\n raise,\n shallow,\n} from \"@liveblocks/core\";\nimport type { PropsWithChildren } from \"react\";\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n} from \"react\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport { useSyncExternalStoreWithSelector } from \"use-sync-external-store/shim/with-selector.js\";\n\nimport { config } from \"./config\";\nimport { useIsInsideRoom } from \"./contexts\";\nimport { shallow2 } from \"./lib/shallow2\";\nimport { useInitial, useInitialUnlessFunction } from \"./lib/use-initial\";\nimport { useLatest } from \"./lib/use-latest\";\nimport { use } from \"./lib/use-polyfill\";\nimport type {\n InboxNotificationsAsyncResult,\n LiveblocksContextBundle,\n RoomInfoAsyncResult,\n RoomInfoAsyncSuccess,\n SharedContextBundle,\n ThreadsAsyncResult,\n ThreadsAsyncSuccess,\n UnreadInboxNotificationsCountAsyncResult,\n UserAsyncResult,\n UserAsyncSuccess,\n UseSyncStatusOptions,\n UseUserThreadsOptions,\n} from \"./types\";\nimport { UmbrellaStore } from \"./umbrella-store\";\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\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 identity<T>(x: T): T {\n return x;\n}\n\nconst _umbrellaStores = new WeakMap<\n OpaqueClient,\n UmbrellaStore<BaseMetadata>\n>();\nconst _extras = new WeakMap<\n OpaqueClient,\n ReturnType<typeof makeLiveblocksExtrasForClient>\n>();\nconst _bundles = new WeakMap<\n OpaqueClient,\n LiveblocksContextBundle<BaseUserMeta, BaseMetadata>\n>();\n\nfunction selectUnreadInboxNotificationsCount(\n inboxNotifications: readonly InboxNotificationData[]\n) {\n let count = 0;\n\n for (const notification of inboxNotifications) {\n if (\n notification.readAt === null ||\n notification.readAt < notification.notifiedAt\n ) {\n count++;\n }\n }\n\n return count;\n}\n\nfunction selectorFor_useUnreadInboxNotificationsCount(\n result: InboxNotificationsAsyncResult\n): UnreadInboxNotificationsCountAsyncResult {\n if (!result.inboxNotifications) {\n // Can be loading or error states\n return result;\n }\n\n // OK state\n return {\n isLoading: false,\n count: selectUnreadInboxNotificationsCount(result.inboxNotifications),\n };\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 getOrCreateContextBundle<\n U extends BaseUserMeta,\n M extends BaseMetadata,\n>(client: OpaqueClient): LiveblocksContextBundle<U, M> {\n let bundle = _bundles.get(client);\n if (!bundle) {\n bundle = makeLiveblocksContextBundle(client);\n _bundles.set(client, bundle);\n }\n return bundle as LiveblocksContextBundle<U, M>;\n}\n\n/**\n * Gets or creates a unique Umbrella store for each unique client instance.\n *\n * @private\n */\nexport function getUmbrellaStoreForClient<M extends BaseMetadata>(\n client: OpaqueClient\n): UmbrellaStore<M> {\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<M>;\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<M extends BaseMetadata>(\n client: OpaqueClient\n) {\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<M>;\n };\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 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 return {\n store,\n notificationsPoller,\n userThreadsPoller,\n };\n}\n\nfunction makeLiveblocksContextBundle<\n U extends BaseUserMeta,\n M extends BaseMetadata,\n>(client: Client<U>): LiveblocksContextBundle<U, M> {\n // Bind all hooks to the current client instance\n const useInboxNotificationThread = (inboxNotificationId: string) =>\n useInboxNotificationThread_withClient<M>(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 // 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, M> = {\n LiveblocksProvider,\n\n useInboxNotifications: () =>\n useInboxNotifications_withClient(client, identity, shallow),\n useUnreadInboxNotificationsCount: () =>\n useUnreadInboxNotificationsCount_withClient(client),\n\n useMarkInboxNotificationAsRead,\n useMarkAllInboxNotificationsAsRead,\n\n useDeleteInboxNotification,\n useDeleteAllInboxNotifications,\n\n useInboxNotificationThread,\n useUserThreads_experimental,\n\n ...shared.classic,\n\n suspense: {\n LiveblocksProvider,\n\n useInboxNotifications: () =>\n useInboxNotificationsSuspense_withClient(client),\n useUnreadInboxNotificationsCount: () =>\n useUnreadInboxNotificationsCountSuspense_withClient(client),\n\n useMarkInboxNotificationAsRead,\n useMarkAllInboxNotificationsAsRead,\n\n useDeleteInboxNotification,\n useDeleteAllInboxNotifications,\n\n useInboxNotificationThread,\n\n useUserThreads_experimental: useUserThreadsSuspense_experimental,\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): T {\n const { store, notificationsPoller: poller } =\n getLiveblocksExtrasForClient(client);\n\n // Trigger initial loading of inbox notifications if it hasn't started\n // already, but don't await its promise.\n useEffect(() => {\n void store.waitUntilNotificationsLoaded();\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 useSyncExternalStoreWithSelector(\n store.subscribe,\n store.getInboxNotificationsLoadingState,\n store.getInboxNotificationsLoadingState,\n selector,\n isEqual\n );\n}\n\nfunction useInboxNotificationsSuspense_withClient(client: OpaqueClient) {\n const store = getLiveblocksExtrasForClient(client).store;\n\n // Suspend until there are at least some inbox notifications\n use(store.waitUntilNotificationsLoaded());\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(client, identity, shallow);\n assert(!result.error, \"Did not expect error\");\n assert(!result.isLoading, \"Did not expect loading\");\n return result;\n}\n\nfunction useUnreadInboxNotificationsCount_withClient(client: OpaqueClient) {\n return useInboxNotifications_withClient(\n client,\n selectorFor_useUnreadInboxNotificationsCount,\n shallow\n );\n}\n\nfunction useUnreadInboxNotificationsCountSuspense_withClient(\n client: OpaqueClient\n) {\n const store = getLiveblocksExtrasForClient(client).store;\n\n // Suspend until there are at least some inbox notifications\n use(store.waitUntilNotificationsLoaded());\n\n const result = useUnreadInboxNotificationsCount_withClient(client);\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 } = getLiveblocksExtrasForClient(client);\n\n const readAt = new Date();\n const optimisticUpdateId = store.addOptimisticUpdate({\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.updateInboxNotification(\n inboxNotificationId,\n optimisticUpdateId,\n (inboxNotification) => ({ ...inboxNotification, readAt })\n );\n },\n () => {\n // TODO: Broadcast errors to client\n store.removeOptimisticUpdate(optimisticUpdateId);\n }\n );\n },\n [client]\n );\n}\n\nfunction useMarkAllInboxNotificationsAsRead_withClient(client: OpaqueClient) {\n return useCallback(() => {\n const { store } = getLiveblocksExtrasForClient(client);\n const readAt = new Date();\n const optimisticUpdateId = store.addOptimisticUpdate({\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.updateAllInboxNotifications(\n optimisticUpdateId,\n (inboxNotification) => ({ ...inboxNotification, readAt })\n );\n },\n () => {\n // TODO: Broadcast errors to client\n store.removeOptimisticUpdate(optimisticUpdateId);\n }\n );\n }, [client]);\n}\n\nfunction useDeleteInboxNotification_withClient(client: OpaqueClient) {\n return useCallback(\n (inboxNotificationId: string) => {\n const { store } = getLiveblocksExtrasForClient(client);\n\n const deletedAt = new Date();\n const optimisticUpdateId = store.addOptimisticUpdate({\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(\n inboxNotificationId,\n optimisticUpdateId\n );\n },\n () => {\n // TODO: Broadcast errors to client\n store.removeOptimisticUpdate(optimisticUpdateId);\n }\n );\n },\n [client]\n );\n}\n\nfunction useDeleteAllInboxNotifications_withClient(client: OpaqueClient) {\n return useCallback(() => {\n const { store } = getLiveblocksExtrasForClient(client);\n const deletedAt = new Date();\n const optimisticUpdateId = store.addOptimisticUpdate({\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(optimisticUpdateId);\n },\n () => {\n // TODO: Broadcast errors to client\n store.removeOptimisticUpdate(optimisticUpdateId);\n }\n );\n }, [client]);\n}\n\nfunction useInboxNotificationThread_withClient<M extends BaseMetadata>(\n client: OpaqueClient,\n inboxNotificationId: string\n): ThreadData<M> {\n const { store } = getLiveblocksExtrasForClient<M>(client);\n\n const getter = store.getFullState;\n\n const selector = useCallback(\n (state: ReturnType<typeof getter>) => {\n const inboxNotification =\n state.notificationsById[inboxNotificationId] ??\n raise(`Inbox notification with ID \"${inboxNotificationId}\" not found`);\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 return useSyncExternalStoreWithSelector(\n store.subscribe, // Re-evaluate if we need to update any time the notification changes over time\n getter,\n getter,\n selector\n );\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.getState(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 // NOTE: .get() will trigger any actual fetches, whereas .getState() will not,\n // and it won't trigger a fetch if we already have data\n void usersStore.get(userId);\n }, [usersStore, userId, result]);\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.getState(userId),\n [usersStore, userId]\n );\n const userState = getUserState();\n\n if (!userState || userState.isLoading) {\n throw usersStore.get(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.getState(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 // NOTE: .get() will trigger any actual fetches, whereas .getState() will not,\n // and it won't trigger a fetch if we already have data\n void roomsInfoStore.get(roomId);\n }, [roomsInfoStore, roomId, result]);\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.getState(roomId),\n [roomsInfoStore, roomId]\n );\n const roomInfoState = getRoomInfoState();\n\n if (!roomInfoState || roomInfoState.isLoading) {\n throw roomsInfoStore.get(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\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 useIsInsideRoom,\n useSyncStatus,\n },\n suspense: {\n useClient,\n useUser: (userId: string) => useUserSuspense_withClient(client, userId),\n useRoomInfo: (roomId: string) =>\n useRoomInfoSuspense_withClient(client, roomId),\n useIsInsideRoom,\n useSyncStatus,\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 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 * @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 unstable_fallbackToHTTP: useInitial(o.unstable_fallbackToHTTP),\n unstable_streamData: useInitial(o.unstable_streamData),\n preventUnsavedChanges: useInitial(o.preventUnsavedChanges),\n\n authEndpoint: useInitialUnlessFunction(o.authEndpoint),\n resolveMentionSuggestions: useInitialUnlessFunction(\n o.resolveMentionSuggestions\n ),\n resolveUsers: useInitialUnlessFunction(o.resolveUsers),\n resolveRoomsInfo: useInitialUnlessFunction(o.resolveRoomsInfo),\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 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 M extends BaseMetadata = DM,\n>(client: OpaqueClient): LiveblocksContextBundle<U, M> {\n return getOrCreateContextBundle<U, M>(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<M extends BaseMetadata>(\n options: UseUserThreadsOptions<M> = {\n query: {\n metadata: {},\n },\n }\n): ThreadsAsyncResult<M> {\n const client = useClient();\n\n const { store, userThreadsPoller: poller } =\n getLiveblocksExtrasForClient<M>(client);\n\n useEffect(\n () => {\n void store.waitUntilUserThreadsLoaded(options.query);\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 getter = useCallback(\n () => store.getUserThreadsLoadingState(options.query),\n [store, options.query]\n );\n\n return useSyncExternalStoreWithSelector(\n store.subscribe,\n getter,\n getter,\n identity,\n shallow2 // NOTE: Using 2-level-deep shallow check here, because the result of selectThreads() is not stable!\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<M extends BaseMetadata>(\n options: UseUserThreadsOptions<M> = {\n query: {\n metadata: {},\n },\n }\n): ThreadsAsyncSuccess<M> {\n const client = useClient();\n\n const { store } = getLiveblocksExtrasForClient<M>(client);\n\n use(store.waitUntilUserThreadsLoaded(options.query));\n\n const result = useUserThreads_experimental(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() {\n return useInboxNotifications_withClient(useClient(), identity, shallow);\n}\n\n/**\n * Returns the inbox notifications for the current user.\n *\n * @example\n * const { inboxNotifications } = useInboxNotifications();\n */\nfunction useInboxNotificationsSuspense() {\n return useInboxNotificationsSuspense_withClient(useClient());\n}\n\nfunction useInboxNotificationThread<M extends BaseMetadata>(\n inboxNotificationId: string\n) {\n return useInboxNotificationThread_withClient<M>(\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 return useUnreadInboxNotificationsCount_withClient(useClient());\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 return useUnreadInboxNotificationsCountSuspense_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\ntype TypedBundle = LiveblocksContextBundle<DU, DM>;\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\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] = React.useState(getter);\n const oldStatus = useLatest(getter());\n\n React.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// 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 useRoomInfo,\n useRoomInfoSuspense,\n useSyncStatus,\n useUnreadInboxNotificationsCount,\n useUnreadInboxNotificationsCountSuspense,\n _useUserThreads_experimental as useUserThreads_experimental,\n _useUserThreadsSuspense_experimental as useUserThreadsSuspense_experimental,\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: 5 * SECONDS,\n\n HISTORY_VERSIONS_POLL_INTERVAL: 1 * MINUTES,\n HISTORY_VERSIONS_MAX_STALE_TIME: 5 * SECONDS,\n\n NOTIFICATION_SETTINGS_POLL_INTERVAL: 1 * MINUTES,\n NOTIFICATION_SETTINGS_MAX_STALE_TIME: 5 * SECONDS,\n};\n","import { isPlainObject, shallow } from \"@liveblocks/core\";\n\n/**\n * Two-level deep shallow check.\n * Useful for checking equality of { isLoading: false, myData: [ ... ] } like\n * data structures, where you want to do a shallow comparison on the \"data\"\n * key.\n *\n * NOTE: Works on objects only, not on arrays!\n */\n// TODO Ideally we won't need this shallow2 helper anymore, so let's aim to remove it!\nexport function shallow2(a: unknown, b: unknown): boolean {\n if (!isPlainObject(a) || !isPlainObject(b)) {\n return shallow(a, b);\n }\n\n const keysA = Object.keys(a);\n if (keysA.length !== Object.keys(b).length) {\n return false;\n }\n\n return keysA.every(\n (key) =>\n Object.prototype.hasOwnProperty.call(b, key) && shallow(a[key], b[key])\n );\n}\n","import type { Reducer } from \"react\";\nimport { useCallback, useReducer } from \"react\";\n\nimport { useLatest } from \"./use-latest\";\n\nconst noop = <T>(state: T) => state;\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): T {\n // Equivalent to useState(() => value)[0], but slightly more low-level\n return useReducer<Reducer<T, unknown>>(noop, value)[0];\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>(latestValue: T): T {\n const frozenValue = useInitial(latestValue);\n\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 if (typeof frozenValue === \"function\") {\n type Fn = T & ((...args: unknown[]) => unknown);\n const ref = useLatest(latestValue as Fn);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useCallback(((...args: unknown[]) => ref.current(...args)) as Fn, [\n ref,\n ]);\n } else {\n return frozenValue;\n }\n /* eslint-enable react-hooks/rules-of-hooks */\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 React from \"react\";\n\n/**\n * Drop-in replacement for React 19's `use` hook.\n */\nexport const use =\n // React.use ||\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 AsyncResult,\n BaseMetadata,\n BaseUserMeta,\n Client,\n CommentData,\n CommentReaction,\n CommentUserReaction,\n DistributiveOmit,\n EventSource,\n HistoryVersion,\n InboxNotificationData,\n InboxNotificationDeleteInfo,\n Observable,\n OpaqueClient,\n Patchable,\n Permission,\n Resolve,\n RoomNotificationSettings,\n Store,\n SyncSource,\n ThreadData,\n ThreadDataWithDeleteInfo,\n ThreadDeleteInfo,\n} from \"@liveblocks/core\";\nimport {\n autoRetry,\n compactObject,\n console,\n createStore,\n HttpError,\n kInternal,\n makeEventSource,\n mapValues,\n nanoid,\n nn,\n stringify,\n} from \"@liveblocks/core\";\n\nimport { autobind } from \"./lib/autobind\";\nimport type { ReadonlyThreadDB } from \"./ThreadDB\";\nimport { ThreadDB } from \"./ThreadDB\";\nimport type {\n InboxNotificationsAsyncResult,\n RoomNotificationSettingsAsyncResult,\n ThreadsAsyncResult,\n ThreadsQuery,\n} from \"./types\";\n\ntype OptimisticUpdate<M extends BaseMetadata> =\n | CreateThreadOptimisticUpdate<M>\n | DeleteThreadOptimisticUpdate\n | EditThreadMetadataOptimisticUpdate<M>\n | MarkThreadAsResolvedOptimisticUpdate\n | MarkThreadAsUnresolvedOptimisticUpdate\n | CreateCommentOptimisticUpdate\n | EditCommentOptimisticUpdate\n | DeleteCommentOptimisticUpdate\n | AddReactionOptimisticUpdate\n | RemoveReactionOptimisticUpdate\n | MarkInboxNotificationAsReadOptimisticUpdate\n | MarkAllInboxNotificationsAsReadOptimisticUpdate\n | DeleteInboxNotificationOptimisticUpdate\n | DeleteAllInboxNotificationsOptimisticUpdate\n | UpdateNotificationSettingsOptimisticUpdate;\n\ntype CreateThreadOptimisticUpdate<M extends BaseMetadata> = {\n type: \"create-thread\";\n id: string;\n roomId: string;\n thread: ThreadData<M>;\n};\n\ntype DeleteThreadOptimisticUpdate = {\n type: \"delete-thread\";\n id: string;\n roomId: string;\n threadId: string;\n deletedAt: Date;\n};\n\ntype EditThreadMetadataOptimisticUpdate<M extends BaseMetadata> = {\n type: \"edit-thread-metadata\";\n id: string;\n threadId: string;\n metadata: Resolve<Patchable<M>>;\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 CreateCommentOptimisticUpdate = {\n type: \"create-comment\";\n id: string;\n comment: CommentData;\n};\n\ntype EditCommentOptimisticUpdate = {\n type: \"edit-comment\";\n id: string;\n comment: CommentData;\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 UpdateNotificationSettingsOptimisticUpdate = {\n type: \"update-notification-settings\";\n id: string;\n roomId: string;\n settings: Partial<RoomNotificationSettings>;\n};\n\ntype PaginationState = {\n cursor: string | null; // If `null`, it's the last page\n isFetchingMore: boolean;\n fetchMoreError?: Error;\n};\n\n/**\n * Valid combinations of field patches to the pagination state.\n */\ntype PaginationStatePatch =\n | { isFetchingMore: true }\n | {\n isFetchingMore: false;\n cursor: string | null;\n fetchMoreError: undefined;\n }\n | { isFetchingMore: false; fetchMoreError: Error };\n\n/**\n * Example:\n * generateQueryKey('room-abc', { xyz: 123, abc: \"red\" })\n * → 'room-abc-{\"color\":\"red\",\"xyz\":123}'\n */\nfunction makeRoomThreadsQueryKey(\n roomId: string,\n query: ThreadsQuery<BaseMetadata> | undefined\n) {\n return `${roomId}-${stringify(query ?? {})}`;\n}\n\nfunction makeUserThreadsQueryKey(\n query: ThreadsQuery<BaseMetadata> | undefined\n) {\n return `USER_THREADS:${stringify(query ?? {})}`;\n}\n\nfunction makeNotificationSettingsQueryKey(roomId: string) {\n return `${roomId}:NOTIFICATION_SETTINGS`;\n}\n\nfunction makeVersionsQueryKey(roomId: string) {\n return `${roomId}-VERSIONS`;\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\nconst ASYNC_LOADING = Object.freeze({ isLoading: true });\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 public readonly observable: Observable<void>;\n private _eventSource: EventSource<void>;\n private _fetchPage: (cursor?: string) => Promise<string | null>;\n private _paginationState: PaginationState | null; // Should be null while in loading or error state!\n private _pendingFetchMore: Promise<void> | null;\n\n constructor(fetchPage: (cursor?: string) => Promise<string | null>) {\n this._paginationState = null;\n this._fetchPage = fetchPage;\n this._eventSource = makeEventSource<void>();\n this._pendingFetchMore = null;\n this.observable = this._eventSource.observable;\n\n autobind(this);\n }\n\n private patchPaginationState(patch: PaginationStatePatch): void {\n const state = this._paginationState;\n if (state === null) return;\n this._paginationState = { ...state, ...patch };\n this._eventSource.notify();\n }\n\n private async _fetchMore(): Promise<void> {\n const state = this._paginationState;\n if (!state?.cursor) {\n // Do nothing if we don't have a cursor to work with. It means:\n // - We don't have a cursor yet (we haven't loaded the first page yet); or\n // - We don't have a cursor any longer (we're already on the\n // last page)\n return;\n }\n\n this.patchPaginationState({ isFetchingMore: true });\n try {\n const nextCursor = await this._fetchPage(state.cursor);\n this.patchPaginationState({\n cursor: nextCursor,\n fetchMoreError: undefined,\n isFetchingMore: false,\n });\n } catch (err) {\n this.patchPaginationState({\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._paginationState;\n if (state?.cursor === null) {\n return noop;\n }\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 public get(): AsyncResult<{\n fetchMore: () => void;\n fetchMoreError?: Error;\n hasFetchedAll: boolean;\n isFetchingMore: boolean;\n }> {\n const usable = this._cachedPromise;\n if (usable === null || usable.status === \"pending\") {\n return ASYNC_LOADING;\n }\n\n if (usable.status === \"rejected\") {\n return { isLoading: false, error: usable.reason };\n }\n\n const state = this._paginationState!;\n return {\n isLoading: false,\n data: {\n fetchMore: this.fetchMore as () => void,\n isFetchingMore: state.isFetchingMore,\n fetchMoreError: state.fetchMoreError,\n hasFetchedAll: state.cursor === null,\n },\n };\n }\n\n private _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 = autoRetry(\n () => this._fetchPage(/* cursor */ undefined),\n 5,\n [5000, 5000, 10000, 15000]\n );\n\n const promise = usify(\n initialFetcher.then((cursor) => {\n // Initial fetch completed\n this._paginationState = {\n cursor,\n isFetchingMore: false,\n fetchMoreError: undefined,\n };\n })\n );\n\n // TODO for later: Maybe move this into the .then() above too?\n promise.then(\n () => this._eventSource.notify(),\n () => {\n this._eventSource.notify();\n\n // Wait for 5 seconds before removing the request from the cache\n setTimeout(() => {\n this._cachedPromise = null;\n this._eventSource.notify();\n }, 5_000);\n }\n );\n\n this._cachedPromise = promise;\n return promise;\n }\n}\n\nexport class SinglePageResource {\n public readonly observable: Observable<void>;\n private _eventSource: EventSource<void>;\n private _fetchPage: () => Promise<void>;\n\n constructor(fetchPage: () => Promise<void>) {\n this._fetchPage = fetchPage;\n this._eventSource = makeEventSource<void>();\n this.observable = this._eventSource.observable;\n\n autobind(this);\n }\n\n public get(): AsyncResult<undefined> {\n const usable = this._cachedPromise;\n if (usable === null || usable.status === \"pending\") {\n return ASYNC_LOADING;\n }\n\n if (usable.status === \"rejected\") {\n return { isLoading: false, error: usable.reason };\n }\n\n return {\n isLoading: false,\n data: undefined,\n };\n }\n\n private _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 = autoRetry(\n () => this._fetchPage(),\n 5,\n [5000, 5000, 10000, 15000]\n );\n\n const promise = usify(initialFetcher);\n\n // TODO for later: Maybe move this into the .then() above too?\n promise.then(\n () => this._eventSource.notify(),\n () => {\n this._eventSource.notify();\n\n // Wait for 5 seconds before removing the request from the cache\n setTimeout(() => {\n this._cachedPromise = null;\n this._eventSource.notify();\n }, 5_000);\n }\n );\n\n this._cachedPromise = promise;\n return promise;\n }\n}\n\ntype InternalState<M extends BaseMetadata> = Readonly<{\n optimisticUpdates: readonly OptimisticUpdate<M>[];\n permissionsByRoom: Record<string, Set<Permission>>;\n\n // TODO: Ideally we would have a similar NotificationsDB, like we have ThreadDB\n notificationsById: Record<string, InboxNotificationData>;\n settingsByRoomId: Record<string, RoomNotificationSettings>;\n versionsByRoomId: Record<string, Record<string, HistoryVersion>>;\n}>;\n\n/**\n * Externally observable state of the store, which will have:\n * - Optimistic updates applied\n * - All deleted threads removed from the threads list\n */\nexport type UmbrellaStoreState<M 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\n // TODO: This should not get exposed via the \"full state\". Instead, we should\n // expose it via a cached `.getThreadDB()`, and invalidate this cached\n // value if either the threads change or a (thread) optimistic update is\n // changed.\n threadsDB: ReadonlyThreadDB<M>;\n\n /**\n * All inbox notifications in a sorted array, optimistic updates applied.\n */\n cleanedNotifications: InboxNotificationData[];\n\n /**\n * Inbox notifications by ID.\n * e.g. `in_${string}`\n */\n notificationsById: Record<string, InboxNotificationData>;\n\n /**\n * Notification 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 */\n settingsByRoomId: Record<string, RoomNotificationSettings>;\n /**\n * Versions by roomId\n * e.g. { 'room-abc': {versions: \"all versions\"}}\n */\n versionsByRoomId: Record<string, Record<string, HistoryVersion>>;\n};\n\nexport class UmbrellaStore<M extends BaseMetadata> {\n private _client: Client<BaseUserMeta, M>;\n private _syncSource: SyncSource;\n\n // Raw threads DB (without any optimistic updates applied)\n private _rawThreadsDB: ThreadDB<M>;\n private _prevVersion: number = -1;\n\n private _store: Store<InternalState<M>>;\n private _prevState: InternalState<M> | null = null;\n private _stateCached: UmbrellaStoreState<M> | null = null;\n\n // Notifications\n private _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 private _notifications: PaginatedResource;\n\n // Room Threads\n private _roomThreadsLastRequestedAtByRoom = new Map<string, Date>();\n private _roomThreads: Map<string, PaginatedResource> = new Map();\n\n // User Threads\n private _userThreadsLastRequestedAt: Date | null = null;\n private _userThreads: Map<string, PaginatedResource> = new Map();\n\n // Room versions\n private _roomVersions: Map<string, SinglePageResource> = new Map();\n private _roomVersionsLastRequestedAtByRoom = new Map<string, Date>();\n\n // Room notification settings\n private _roomNotificationSettings: Map<string, SinglePageResource> =\n new Map();\n\n constructor(client: OpaqueClient) {\n this._client = client[kInternal].as<M>();\n this._syncSource = this._client[kInternal].createSyncSource();\n\n const inboxFetcher = async (cursor?: string) => {\n const result = await this._client.getInboxNotifications({ cursor });\n\n this.updateThreadsAndNotifications(\n result.threads,\n result.inboxNotifications\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 this._notifications = new PaginatedResource(inboxFetcher);\n this._notifications.observable.subscribe(() =>\n // Note that the store itself does not change, but it's only vehicle at\n // the moment to trigger a re-render, so we'll do a no-op update here.\n this._store.set((store) => ({ ...store }))\n );\n\n this._rawThreadsDB = new ThreadDB();\n this._store = createStore<InternalState<M>>({\n optimisticUpdates: [],\n permissionsByRoom: {},\n notificationsById: {},\n settingsByRoomId: {},\n versionsByRoomId: {},\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 private get(): UmbrellaStoreState<M> {\n // Don't return the raw internal state immediately! Return a new computed\n // cached state (with optimistic updates applied) instead, and cache that\n // until the next .set() call invalidates it.\n const rawState = this._store.get();\n if (\n this._prevVersion !== this._rawThreadsDB.version || // Note: Version check is only needed temporarily, until we can get rid of the Zustand-like update model\n this._prevState !== rawState ||\n this._stateCached === null\n ) {\n this._stateCached = internalToExternalState(rawState, this._rawThreadsDB);\n this._prevState = rawState;\n this._prevVersion = this._rawThreadsDB.version;\n }\n return this._stateCached;\n }\n\n public batch(callback: () => void): void {\n return this._store.batch(callback);\n }\n\n public getFullState(): UmbrellaStoreState<M> {\n return this.get();\n }\n\n /**\n * Returns the async result of the given query and room id. If the query is success,\n * then it will return the threads that match that provided query and room id.\n *\n */\n public getRoomThreadsLoadingState(\n roomId: string,\n query: ThreadsQuery<M> | undefined\n ): ThreadsAsyncResult<M> {\n const queryKey = makeRoomThreadsQueryKey(roomId, query);\n\n const paginatedResource = this._roomThreads.get(queryKey);\n if (paginatedResource === undefined) {\n return ASYNC_LOADING;\n }\n\n const asyncResult = paginatedResource.get();\n if (asyncResult.isLoading || asyncResult.error) {\n return asyncResult;\n }\n\n const threads = this.getFullState().threadsDB.findMany(\n roomId,\n query ?? {},\n \"asc\"\n );\n\n const page = asyncResult.data;\n // TODO Memoize this value to ensure stable result, so we won't have to use the selector and isEqual functions!\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 }\n\n public getUserThreadsLoadingState(\n query: ThreadsQuery<M> | undefined\n ): ThreadsAsyncResult<M> {\n const queryKey = makeUserThreadsQueryKey(query);\n\n const paginatedResource = this._userThreads.get(queryKey);\n if (paginatedResource === undefined) {\n return ASYNC_LOADING;\n }\n\n const asyncResult = paginatedResource.get();\n if (asyncResult.isLoading || asyncResult.error) {\n return asyncResult;\n }\n\n const threads = this.getFullState().threadsDB.findMany(\n undefined, // Do _not_ filter by roomId\n query ?? {},\n \"desc\"\n );\n\n const page = asyncResult.data;\n // TODO Memoize this value to ensure stable result, so we won't have to use the selector and isEqual functions!\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 }\n\n // NOTE: This will read the async result, but WILL NOT start loading at the moment!\n public getInboxNotificationsLoadingState(): InboxNotificationsAsyncResult {\n const asyncResult = this._notifications.get();\n if (asyncResult.isLoading || asyncResult.error) {\n return asyncResult;\n }\n\n const page = asyncResult.data;\n // TODO Memoize this value to ensure stable result, so we won't have to use the selector and isEqual functions!\n return {\n isLoading: false,\n inboxNotifications: this.getFullState().cleanedNotifications,\n hasFetchedAll: page.hasFetchedAll,\n isFetchingMore: page.isFetchingMore,\n fetchMoreError: page.fetchMoreError,\n fetchMore: page.fetchMore,\n };\n }\n\n // NOTE: This will read the async result, but WILL NOT start loading at the moment!\n public getNotificationSettingsLoadingState(\n roomId: string\n ): RoomNotificationSettingsAsyncResult {\n const queryKey = makeNotificationSettingsQueryKey(roomId);\n\n const resource = this._roomNotificationSettings.get(queryKey);\n if (resource === undefined) {\n return ASYNC_LOADING;\n }\n\n const asyncResult = resource.get();\n if (asyncResult.isLoading || asyncResult.error) {\n return asyncResult;\n }\n\n // TODO Memoize this value to ensure stable result, so we won't have to use the selector and isEqual functions!\n return {\n isLoading: false,\n settings: nn(this.get().settingsByRoomId[roomId]),\n };\n }\n\n public getRoomVersionsLoadingState(\n roomId: string\n ): AsyncResult<HistoryVersion[], \"versions\"> {\n const queryKey = makeVersionsQueryKey(roomId);\n\n const resource = this._roomVersions.get(queryKey);\n if (resource === undefined) {\n return ASYNC_LOADING;\n }\n\n const asyncResult = resource.get();\n if (asyncResult.isLoading || asyncResult.error) {\n return asyncResult;\n }\n\n // TODO Memoize this value to ensure stable result, so we won't have to use the selector and isEqual functions!\n return {\n isLoading: false,\n versions: Object.values(this.get().versionsByRoomId[roomId] ?? {}),\n };\n }\n\n public subscribe(callback: () => void): () => void {\n return this._store.subscribe(callback);\n }\n\n public _getPermissions(roomId: string): Set<Permission> | undefined {\n return this._store.get().permissionsByRoom[roomId];\n }\n\n // Direct low-level cache mutations ------------------------------------------------- {{{\n\n private mutateThreadsDB(mutate: (db: ThreadDB<M>) => void): void {\n const db = this._rawThreadsDB;\n const old = db.version;\n mutate(db);\n\n // Trigger a re-render only if anything changed in the DB\n if (old !== db.version) {\n this._store.set((state) => ({ ...state }));\n }\n }\n\n private updateInboxNotificationsCache(\n mapFn: (\n cache: Readonly<Record<string, InboxNotificationData>>\n ) => Readonly<Record<string, InboxNotificationData>>\n ): void {\n this._store.set((state) => {\n const inboxNotifications = mapFn(state.notificationsById);\n return inboxNotifications !== state.notificationsById\n ? { ...state, notificationsById: inboxNotifications }\n : state;\n });\n }\n\n private setNotificationSettings(\n roomId: string,\n settings: RoomNotificationSettings\n ): void {\n this._store.set((state) => ({\n ...state,\n settingsByRoomId: {\n ...state.settingsByRoomId,\n [roomId]: settings,\n },\n }));\n }\n\n private updateRoomVersions(roomId: string, versions: HistoryVersion[]): void {\n this._store.set((state) => {\n const versionsById = Object.fromEntries(\n versions.map((version) => [version.id, version])\n );\n\n return {\n ...state,\n versionsByRoomId: {\n ...state.versionsByRoomId,\n [roomId]: {\n // Merge with existing versions for the room, or start with an empty object\n ...(state.versionsByRoomId[roomId] ?? {}),\n ...versionsById,\n },\n },\n };\n });\n }\n\n private updateOptimisticUpdatesCache(\n mapFn: (\n cache: readonly OptimisticUpdate<M>[]\n ) => readonly OptimisticUpdate<M>[]\n ): void {\n this._store.set((state) => {\n const optimisticUpdates = mapFn(state.optimisticUpdates);\n this._syncSource.setSyncStatus(\n optimisticUpdates.length > 0 ? \"synchronizing\" : \"synchronized\"\n );\n return { ...state, optimisticUpdates };\n });\n }\n\n // ---------------------------------------------------------------------------------- }}}\n\n /** @internal - Only call this method from unit tests. */\n public force_set(\n callback: (currentState: InternalState<M>) => InternalState<M>\n ): void {\n return this._store.set(callback);\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 in\n * the cache.\n */\n public updateInboxNotification(\n inboxNotificationId: string,\n optimisticUpdateId: string,\n callback: (\n notification: Readonly<InboxNotificationData>\n ) => Readonly<InboxNotificationData>\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣\n\n // 2️⃣\n this.updateInboxNotificationsCache((cache) => {\n const existing = cache[inboxNotificationId];\n if (!existing) {\n // If the inbox notification doesn't exist in the cache, we do not\n // change anything\n return cache;\n }\n\n const inboxNotifications = {\n ...cache,\n [inboxNotificationId]: callback(existing),\n };\n return inboxNotifications;\n });\n });\n }\n\n /**\n * Updates *all* inbox notifications by running a mapper function over all of\n * them, replacing the corresponding optimistic update.\n */\n public updateAllInboxNotifications(\n optimisticUpdateId: string,\n mapFn: (\n notification: Readonly<InboxNotificationData>\n ) => Readonly<InboxNotificationData>\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣\n this.updateInboxNotificationsCache((cache) => mapValues(cache, mapFn)); // 2️⃣\n });\n }\n\n /**\n * Deletes an existing inbox notification, replacing the corresponding\n * optimistic update.\n */\n public deleteInboxNotification(\n inboxNotificationId: string,\n optimisticUpdateId: string\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣\n\n // 2️⃣\n this.updateInboxNotificationsCache((cache) => {\n // Delete it\n const { [inboxNotificationId]: removed, ...newCache } = cache;\n return removed === undefined ? cache : newCache;\n });\n });\n }\n\n /**\n * Deletes *all* inbox notifications, replacing the corresponding optimistic\n * update.\n */\n public deleteAllInboxNotifications(optimisticUpdateId: string): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣\n this.updateInboxNotificationsCache(() => ({})); // 2️⃣ empty the cache\n });\n }\n\n /**\n * Creates an new thread, replacing the corresponding optimistic update.\n */\n public createThread(\n optimisticUpdateId: string,\n thread: Readonly<ThreadDataWithDeleteInfo<M>>\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣j\n this.mutateThreadsDB((db) => db.upsert(thread)); // 2️⃣\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 in the cache; or\n * - The thread ID was already deleted from the cache; or\n * - The thread ID in the cache was updated more recently than the optimistic\n * update's timestamp (if given)\n */\n private updateThread(\n threadId: string,\n optimisticUpdateId: string | null,\n callback: (\n thread: Readonly<ThreadDataWithDeleteInfo<M>>\n ) => Readonly<ThreadDataWithDeleteInfo<M>>,\n updatedAt?: Date // TODO We could look this up from the optimisticUpdate instead?\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n if (optimisticUpdateId !== null) {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣\n }\n\n // 2️⃣\n this.mutateThreadsDB((db) => {\n const existing = db.get(threadId);\n if (!existing) return;\n if (!!updatedAt && existing.updatedAt > updatedAt) return;\n\n db.upsert(callback(existing));\n });\n });\n }\n\n public patchThread(\n threadId: string,\n optimisticUpdateId: string | null,\n patch: {\n // Only these fields are currently supported to patch\n metadata?: M;\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 optimisticUpdateId,\n (thread) => ({ ...thread, ...compactObject(patch) }),\n updatedAt\n );\n }\n\n public addReaction(\n threadId: string,\n optimisticUpdateId: 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 optimisticUpdateId,\n (thread) => applyAddReaction(thread, commentId, reaction),\n createdAt\n );\n }\n\n public removeReaction(\n threadId: string,\n optimisticUpdateId: string | null,\n commentId: string,\n emoji: string,\n userId: string,\n removedAt: Date\n ): void {\n this.updateThread(\n threadId,\n optimisticUpdateId,\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 in the cache; or\n * - The thread ID was already deleted from the cache\n */\n public deleteThread(\n threadId: string,\n optimisticUpdateId: string | null\n ): void {\n return this.updateThread(\n threadId,\n optimisticUpdateId,\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,\n optimisticUpdateId: string\n ): void {\n // Batch 1️⃣ + 2️⃣ + 3️⃣\n this._store.batch(() => {\n // 1️⃣\n this.removeOptimisticUpdate(optimisticUpdateId);\n\n // If the associated thread is not found, we cannot create a comment under it\n const existingThread = this._rawThreadsDB.get(newComment.threadId);\n if (!existingThread) {\n return;\n }\n\n // 2️⃣ Update the thread instance by adding a comment under it\n this.mutateThreadsDB((db) =>\n db.upsert(applyUpsertComment(existingThread, newComment))\n );\n\n // 3️⃣ Update the associated inbox notification (if any)\n this.updateInboxNotificationsCache((cache) => {\n const existingNotification = Object.values(cache).find(\n (notification) =>\n notification.kind === \"thread\" &&\n notification.threadId === newComment.threadId\n );\n\n if (!existingNotification) {\n // Nothing to update here\n return cache;\n }\n\n // If the thread has an inbox notification associated with it, we update the notification's `notifiedAt` and `readAt` values\n return {\n ...cache,\n [existingNotification.id]: {\n ...existingNotification,\n notifiedAt: newComment.createdAt,\n readAt: newComment.createdAt,\n },\n };\n });\n });\n }\n\n public editComment(\n threadId: string,\n optimisticUpdateId: string,\n editedComment: CommentData\n ): void {\n return this.updateThread(threadId, optimisticUpdateId, (thread) =>\n applyUpsertComment(thread, editedComment)\n );\n }\n\n public deleteComment(\n threadId: string,\n optimisticUpdateId: string,\n commentId: string,\n deletedAt: Date\n ): void {\n return this.updateThread(\n threadId,\n optimisticUpdateId,\n (thread) => applyDeleteComment(thread, commentId, deletedAt),\n deletedAt\n );\n }\n\n public updateThreadAndNotification(\n thread: ThreadData<M>,\n inboxNotification?: InboxNotificationData\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n // 1️⃣\n this.mutateThreadsDB((db) => db.upsertIfNewer(thread));\n\n // 2️⃣\n if (inboxNotification !== undefined) {\n this.updateInboxNotificationsCache((cache) => ({\n ...cache,\n [inboxNotification.id]: inboxNotification,\n }));\n }\n });\n }\n\n public updateThreadsAndNotifications(\n threads: ThreadData<M>[],\n inboxNotifications: InboxNotificationData[]\n ): void;\n public updateThreadsAndNotifications(\n threads: ThreadData<M>[],\n inboxNotifications: InboxNotificationData[],\n deletedThreads: ThreadDeleteInfo[],\n deletedInboxNotifications: InboxNotificationDeleteInfo[]\n ): void;\n public updateThreadsAndNotifications(\n threads: ThreadData<M>[],\n inboxNotifications: InboxNotificationData[],\n deletedThreads: ThreadDeleteInfo[] = [],\n deletedInboxNotifications: InboxNotificationDeleteInfo[] = []\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n // 1️⃣\n this.mutateThreadsDB((db) =>\n applyThreadDeltaUpdates(db, { newThreads: threads, deletedThreads })\n );\n\n // 2️⃣\n this.updateInboxNotificationsCache((cache) =>\n applyNotificationsUpdates(cache, {\n newInboxNotifications: inboxNotifications,\n deletedNotifications: deletedInboxNotifications,\n })\n );\n });\n }\n\n /**\n * Updates existing notification setting for a room with a new value,\n * replacing the corresponding optimistic update.\n */\n public updateRoomNotificationSettings_confirmOptimisticUpdate(\n roomId: string,\n optimisticUpdateId: string,\n settings: Readonly<RoomNotificationSettings>\n ): void {\n // Batch 1️⃣ + 2️⃣\n this._store.batch(() => {\n this.removeOptimisticUpdate(optimisticUpdateId); // 1️⃣\n this.setNotificationSettings(roomId, settings); // 2️⃣\n });\n }\n\n public addOptimisticUpdate(\n optimisticUpdate: DistributiveOmit<OptimisticUpdate<M>, \"id\">\n ): string {\n const id = nanoid();\n const newUpdate: OptimisticUpdate<M> = { ...optimisticUpdate, id };\n this.updateOptimisticUpdatesCache((cache) => [...cache, newUpdate]);\n return id;\n }\n\n public removeOptimisticUpdate(optimisticUpdateId: string): void {\n this.updateOptimisticUpdatesCache((cache) =>\n cache.filter((ou) => ou.id !== optimisticUpdateId)\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.updateThreadsAndNotifications(\n result.threads.updated,\n result.inboxNotifications.updated,\n result.threads.deleted,\n result.inboxNotifications.deleted\n );\n }\n\n public waitUntilNotificationsLoaded(): UsablePromise<void> {\n return this._notifications.waitUntilLoaded();\n }\n\n private updateRoomPermissions(permissions: Record<string, Permission[]>) {\n const permissionsByRoom = { ...this._store.get().permissionsByRoom };\n\n Object.entries(permissions).forEach(([roomId, newPermissions]) => {\n // Get the existing set of permissions for the room and only ever add permission to this set\n const existingPermissions = permissionsByRoom[roomId] ?? new Set();\n // Add the new permissions to the set of existing permissions\n newPermissions.forEach((permission) =>\n existingPermissions.add(permission)\n );\n permissionsByRoom[roomId] = existingPermissions;\n });\n\n this._store.set((state) => ({\n ...state,\n permissionsByRoom,\n }));\n }\n\n public waitUntilRoomThreadsLoaded(\n roomId: string,\n query: ThreadsQuery<M> | undefined\n ) {\n const threadsFetcher = async (cursor?: string) => {\n const result = await this._client[kInternal].httpClient.getThreads({\n roomId,\n cursor,\n query,\n });\n this.updateThreadsAndNotifications(\n result.threads,\n result.inboxNotifications\n );\n\n this.updateRoomPermissions(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(roomId, result.requestedAt);\n }\n\n return result.nextCursor;\n };\n\n const queryKey = makeRoomThreadsQueryKey(roomId, query);\n let paginatedResource = this._roomThreads.get(queryKey);\n if (paginatedResource === undefined) {\n paginatedResource = new PaginatedResource(threadsFetcher);\n }\n\n paginatedResource.observable.subscribe(() =>\n // Note that the store itself does not change, but it's only vehicle at\n // the moment to trigger a re-render, so we'll do a no-op update here.\n this._store.set((store) => ({ ...store }))\n );\n\n this._roomThreads.set(queryKey, paginatedResource);\n\n return paginatedResource.waitUntilLoaded();\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.updateThreadsAndNotifications(\n updates.threads.updated,\n updates.inboxNotifications.updated,\n updates.threads.deleted,\n updates.inboxNotifications.deleted\n );\n\n this.updateRoomPermissions(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 waitUntilUserThreadsLoaded(query: ThreadsQuery<M> | undefined) {\n const queryKey = makeUserThreadsQueryKey(query);\n\n const threadsFetcher = async (cursor?: string) => {\n const result = await this._client[\n kInternal\n ].httpClient.getUserThreads_experimental({\n cursor,\n query,\n });\n this.updateThreadsAndNotifications(\n result.threads,\n result.inboxNotifications\n );\n\n this.updateRoomPermissions(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 let paginatedResource = this._userThreads.get(queryKey);\n if (paginatedResource === undefined) {\n paginatedResource = new PaginatedResource(threadsFetcher);\n }\n\n paginatedResource.observable.subscribe(() =>\n // Note that the store itself does not change, but it's only vehicle at\n // the moment to trigger a re-render, so we'll do a no-op update here.\n this._store.set((store) => ({ ...store }))\n );\n\n this._userThreads.set(queryKey, paginatedResource);\n\n return paginatedResource.waitUntilLoaded();\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.updateThreadsAndNotifications(\n result.threads.updated,\n result.inboxNotifications.updated,\n result.threads.deleted,\n result.inboxNotifications.deleted\n );\n\n this.updateRoomPermissions(result.permissionHints);\n }\n\n public waitUntilRoomVersionsLoaded(roomId: string) {\n const queryKey = makeVersionsQueryKey(roomId);\n let resource = this._roomVersions.get(queryKey);\n if (resource === undefined) {\n const versionsFetcher = async () => {\n const room = this._client.getRoom(roomId);\n if (room === null) {\n throw new HttpError(\n `Room '${roomId}' is not available on client`,\n 479\n );\n }\n\n const result = await room[kInternal].listTextVersions();\n this.updateRoomVersions(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 resource = new SinglePageResource(versionsFetcher);\n }\n\n resource.observable.subscribe(() =>\n // Note that the store itself does not change, but it's only vehicle at\n // the moment to trigger a re-render, so we'll do a no-op update here.\n this._store.set((store) => ({ ...store }))\n );\n\n this._roomVersions.set(queryKey, resource);\n\n return resource.waitUntilLoaded();\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.updateRoomVersions(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 waitUntilRoomNotificationSettingsLoaded(roomId: string) {\n const queryKey = makeNotificationSettingsQueryKey(roomId);\n let resource = this._roomNotificationSettings.get(queryKey);\n if (resource === undefined) {\n const notificationSettingsFetcher = async () => {\n const room = this._client.getRoom(roomId);\n if (room === null) {\n throw new HttpError(\n `Room '${roomId}' is not available on client`,\n 479\n );\n }\n\n const result = await room.getNotificationSettings();\n this.setNotificationSettings(roomId, result);\n };\n\n resource = new SinglePageResource(notificationSettingsFetcher);\n }\n\n resource.observable.subscribe(() =>\n // Note that the store itself does not change, but it's only vehicle at\n // the moment to trigger a re-render, so we'll do a no-op update here.\n this._store.set((store) => ({ ...store }))\n );\n\n this._roomNotificationSettings.set(queryKey, resource);\n\n return resource.waitUntilLoaded();\n }\n\n public async refreshRoomNotificationSettings(\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.getNotificationSettings({ signal });\n this.setNotificationSettings(roomId, result);\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 internalToExternalState<M extends BaseMetadata>(\n state: InternalState<M>,\n rawThreadsDB: ThreadDB<M>\n): UmbrellaStoreState<M> {\n const threadsDB = rawThreadsDB.clone();\n\n const computed = {\n notificationsById: { ...state.notificationsById },\n settingsByRoomId: { ...state.settingsByRoomId },\n };\n\n for (const optimisticUpdate of state.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(\n computed.notificationsById\n ).find(\n (notification) =>\n notification.kind === \"thread\" &&\n notification.threadId === thread.id\n );\n\n if (inboxNotification === undefined) {\n break;\n }\n\n computed.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 \"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 =\n computed.notificationsById[optimisticUpdate.inboxNotificationId];\n\n // If the inbox notification doesn't exist in the cache, we do not apply the update\n if (ibn === undefined) {\n break;\n }\n\n computed.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 computed.notificationsById) {\n const ibn = computed.notificationsById[id];\n\n // If the inbox notification doesn't exist in the cache, we do not apply the update\n if (ibn === undefined) {\n break;\n }\n\n computed.notificationsById[id] = {\n ...ibn,\n readAt: optimisticUpdate.readAt,\n };\n }\n break;\n }\n case \"delete-inbox-notification\": {\n delete computed.notificationsById[optimisticUpdate.inboxNotificationId];\n break;\n }\n case \"delete-all-inbox-notifications\": {\n computed.notificationsById = {};\n break;\n }\n\n case \"update-notification-settings\": {\n const settings = computed.settingsByRoomId[optimisticUpdate.roomId];\n\n // If the inbox notification doesn't exist in the cache, we do not apply the update\n if (settings === undefined) {\n break;\n }\n\n computed.settingsByRoomId[optimisticUpdate.roomId] = {\n ...settings,\n ...optimisticUpdate.settings,\n };\n }\n }\n }\n\n // TODO Maybe consider also removing these from the inboxNotificationsById registry?\n const cleanedNotifications =\n // Sort so that the most recent notifications are first\n Object.values(computed.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 cleanedNotifications,\n notificationsById: computed.notificationsById,\n settingsByRoomId: computed.settingsByRoomId,\n threadsDB,\n versionsByRoomId: state.versionsByRoomId,\n };\n}\n\nexport function applyThreadDeltaUpdates<M extends BaseMetadata>(\n db: ThreadDB<M>,\n updates: {\n newThreads: ThreadData<M>[];\n deletedThreads: ThreadDeleteInfo[];\n }\n): void {\n // Add new threads or update existing threads if the existing thread is older than the new thread.\n updates.newThreads.forEach((thread) => db.upsertIfNewer(thread));\n\n // Mark threads in the deletedThreads list as deleted\n updates.deletedThreads.forEach(({ id, deletedAt }) => {\n const existing = db.getEvenIfDeleted(id);\n if (!existing) return;\n\n db.delete(id, deletedAt);\n });\n}\n\nexport function applyNotificationsUpdates(\n existingInboxNotifications: Record<string, InboxNotificationData>,\n updates: {\n newInboxNotifications: InboxNotificationData[];\n deletedNotifications: InboxNotificationDeleteInfo[];\n }\n): Record<string, InboxNotificationData> {\n const updatedInboxNotifications = { ...existingInboxNotifications };\n\n // Add new notifications or update existing notifications if the existing notification is older than the new notification.\n updates.newInboxNotifications.forEach((notification) => {\n const existingNotification = updatedInboxNotifications[notification.id];\n // If the notification already exists, we need to compare the two notifications to determine which one is newer.\n if (existingNotification) {\n const result = compareInboxNotifications(\n existingNotification,\n notification\n );\n\n // If the existing notification is newer than the new notification, we do not update the existing notification.\n if (result === 1) return;\n }\n\n // If the new notification is newer than the existing notification, we update the existing notification.\n updatedInboxNotifications[notification.id] = notification;\n });\n\n updates.deletedNotifications.forEach(\n ({ id }) => delete updatedInboxNotifications[id]\n );\n\n return updatedInboxNotifications;\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<M extends BaseMetadata>(\n thread: ThreadDataWithDeleteInfo<M>,\n comment: CommentData\n): ThreadDataWithDeleteInfo<M> {\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, do not apply the update\n if (existingComment.deletedAt !== undefined) {\n return thread;\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<M extends BaseMetadata>(\n thread: ThreadDataWithDeleteInfo<M>,\n commentId: string,\n deletedAt: Date\n): ThreadDataWithDeleteInfo<M> {\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<M extends BaseMetadata>(\n thread: ThreadDataWithDeleteInfo<M>,\n commentId: string,\n reaction: CommentUserReaction\n): ThreadDataWithDeleteInfo<M> {\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<M extends BaseMetadata>(\n thread: ThreadDataWithDeleteInfo<M>,\n commentId: string,\n emoji: string,\n userId: string,\n removedAt: Date\n): ThreadDataWithDeleteInfo<M> {\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","import type {\n BaseMetadata,\n ThreadData,\n ThreadDataWithDeleteInfo,\n} from \"@liveblocks/core\";\nimport { SortedList } from \"@liveblocks/core\";\n\nimport { makeThreadsFilter } from \"./lib/querying\";\nimport type { ThreadsQuery } from \"./types\";\n\nfunction sanitizeThread<M extends BaseMetadata>(\n thread: ThreadDataWithDeleteInfo<M>\n): ThreadDataWithDeleteInfo<M> {\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<M extends BaseMetadata> = Omit<\n ThreadDB<M>,\n \"upsert\" | \"delete\"\n>;\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<M extends BaseMetadata> {\n private _byId: Map<string, ThreadDataWithDeleteInfo<M>>;\n private _asc: SortedList<ThreadData<M>>;\n private _desc: SortedList<ThreadData<M>>;\n private _version: number; // The version is auto-incremented on every mutation and can be used as a reliable indicator to tell if the contents of the thread pool has changed\n\n constructor() {\n this._asc = SortedList.from<ThreadData<M>>([], (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<M>>([], (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 this._version = 0;\n }\n\n //\n // Public APIs\n //\n\n public clone(): ThreadDB<M> {\n const newPool = new ThreadDB<M>();\n newPool._byId = new Map(this._byId);\n newPool._asc = this._asc.clone();\n newPool._desc = this._desc.clone();\n newPool._version = this._version;\n return newPool;\n }\n\n /** Gets the transaction count for this DB. Increments any time the DB is modified. */\n public get version() {\n return this._version;\n }\n\n /** Returns an existing thread by ID. Will never return a deleted thread. */\n public get(threadId: string): ThreadData<M> | 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<M> | 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<M>): void {\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;\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 this.touch();\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<M>): void {\n const existing = this.get(thread.id);\n if (!existing || thread.updatedAt >= existing.updatedAt) {\n this.upsert(thread);\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 public findMany(\n // TODO: Implement caching here\n roomId: string | undefined,\n query: ThreadsQuery<M>,\n direction: \"asc\" | \"desc\"\n ): ThreadData<M>[] {\n const index = direction === \"desc\" ? this._desc : this._asc;\n const crit: ((thread: ThreadData<M>) => boolean)[] = [];\n if (roomId !== undefined) {\n crit.push((t) => t.roomId === roomId);\n }\n crit.push(makeThreadsFilter(query));\n return Array.from(index.filter((t) => crit.every((pred) => pred(t))));\n }\n\n //\n // Private APIs\n //\n\n private touch() {\n ++this._version;\n }\n}\n","import { isPlainObject } from \"@liveblocks/core\";\n\n/**\n * Check if value is of shape { startsWith: string }\n */\nexport function isStartsWith(blob: unknown): blob is { startsWith: string } {\n return isPlainObject(blob) && isString(blob.startsWith);\n}\n\nexport function isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n","import type { BaseMetadata, ThreadData } from \"@liveblocks/client\";\n\nimport type { ThreadsQuery } from \"../types\";\nimport { isStartsWith, isString } from \"./guards\";\n\n/**\n * Creates a predicate function that will filter all ThreadData instances that\n * match the given query.\n */\nexport function makeThreadsFilter<M extends BaseMetadata>(\n query: ThreadsQuery<M>\n): (thread: ThreadData<M>) => boolean {\n return (thread: ThreadData<M>) =>\n matchesQuery(thread, query) && matchesMetadata(thread, query);\n}\n\nfunction matchesQuery(\n thread: ThreadData<BaseMetadata>,\n q: ThreadsQuery<BaseMetadata>\n) {\n // Boolean logic: query.resolved? => q.resolved === t.resolved\n return q.resolved === undefined || thread.resolved === q.resolved;\n}\n\nfunction matchesMetadata(\n thread: ThreadData<BaseMetadata>,\n q: ThreadsQuery<BaseMetadata>\n) {\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(([key, op]) =>\n // NOTE: `op` can be explicitly-`undefined` here, which ideally would not\n // mean \"filter for absence\" like it does now, as this does not match the\n // backend behavior at the moment. For an in-depth discussion, see\n // https://liveblocks.slack.com/archives/C02PZL7QAAW/p1728546988505989\n matchesOperator(metadata[key], op)\n )\n );\n}\n\nfunction matchesOperator(\n value: BaseMetadata[string],\n // NOTE: Ideally, this should not take `undefined` as a possible `op` value\n // here, see comment above.\n op: BaseMetadata[string] | { startsWith: string } | undefined\n) {\n if (isStartsWith(op)) {\n return isString(value) && value.startsWith(op.startsWith);\n } else {\n return value === op;\n }\n}\n","import type { BaseMetadata, CommentBody, Patchable } from \"@liveblocks/core\";\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class CreateThreadError<M extends BaseMetadata> extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n commentId: string;\n body: CommentBody;\n metadata: M;\n }\n ) {\n super(\"Create thread failed.\");\n this.name = \"CreateThreadError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class DeleteThreadError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n }\n ) {\n super(\"Delete thread failed.\");\n this.name = \"DeleteThreadError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class EditThreadMetadataError<M extends BaseMetadata> extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n metadata: Patchable<M>;\n }\n ) {\n super(\"Edit thread metadata failed.\");\n this.name = \"EditThreadMetadataError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class MarkThreadAsResolvedError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n }\n ) {\n super(\"Mark thread as resolved failed.\");\n this.name = \"MarkThreadAsResolvedError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class MarkThreadAsUnresolvedError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n }\n ) {\n super(\"Mark thread as unresolved failed.\");\n this.name = \"MarkThreadAsUnresolvedError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class CreateCommentError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n commentId: string;\n body: CommentBody;\n }\n ) {\n super(\"Create comment failed.\");\n this.name = \"CreateCommentError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class EditCommentError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n commentId: string;\n body: CommentBody;\n }\n ) {\n super(\"Edit comment failed.\");\n this.name = \"EditCommentError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class DeleteCommentError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n commentId: string;\n }\n ) {\n super(\"Delete comment failed.\");\n this.name = \"DeleteCommentError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class AddReactionError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n commentId: string;\n emoji: string;\n }\n ) {\n super(\"Add reaction failed.\");\n this.name = \"AddReactionError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class RemoveReactionError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n threadId: string;\n commentId: string;\n emoji: string;\n }\n ) {\n super(\"Remove reaction failed.\");\n this.name = \"RemoveReactionError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class MarkInboxNotificationAsReadError extends Error {\n constructor(\n public cause: Error,\n public context: {\n inboxNotificationId: string;\n }\n ) {\n super(\"Mark inbox notification as read failed.\");\n this.name = \"MarkInboxNotificationAsReadError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport class UpdateNotificationSettingsError extends Error {\n constructor(\n public cause: Error,\n public context: {\n roomId: string;\n }\n ) {\n super(\"Update notification settings failed.\");\n this.name = \"UpdateNotificationSettingsError\";\n }\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nexport type CommentsError<M extends BaseMetadata> =\n | CreateThreadError<M>\n | EditThreadMetadataError<M>\n | CreateCommentError\n | EditCommentError\n | DeleteCommentError\n | MarkInboxNotificationAsReadError\n | UpdateNotificationSettingsError;\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 RoomNotificationSettings,\n Status,\n StorageStatus,\n ThreadData,\n User,\n} from \"@liveblocks/client\";\nimport { shallow } from \"@liveblocks/client\";\nimport type {\n AsyncResult,\n CommentsEventServerMsg,\n DE,\n DM,\n DP,\n DS,\n DU,\n EnterOptions,\n LiveblocksError,\n OpaqueClient,\n Poller,\n RoomEventMessage,\n TextEditorType,\n ToImmutable,\n} from \"@liveblocks/core\";\nimport {\n assert,\n console,\n createCommentId,\n createThreadId,\n deprecateIf,\n errorIf,\n HttpError,\n kInternal,\n makeEventSource,\n makePoller,\n ServerMsgCode,\n} from \"@liveblocks/core\";\nimport * as React from \"react\";\nimport { useSyncExternalStoreWithSelector } from \"use-sync-external-store/shim/with-selector.js\";\n\nimport { config } from \"./config\";\nimport { RoomContext, useIsInsideRoom, useRoomOrNull } from \"./contexts\";\nimport { isString } from \"./lib/guards\";\nimport { shallow2 } from \"./lib/shallow2\";\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 useClient,\n useClientOrNull,\n} from \"./liveblocks\";\nimport type {\n AttachmentUrlAsyncResult,\n CommentReactionOptions,\n CreateCommentOptions,\n CreateThreadOptions,\n DeleteCommentOptions,\n EditCommentOptions,\n EditThreadMetadataOptions,\n HistoryVersionDataAsyncResult,\n HistoryVersionsAsyncResult,\n HistoryVersionsAsyncSuccess,\n MutationContext,\n OmitFirstArg,\n RoomContextBundle,\n RoomNotificationSettingsAsyncResult,\n RoomNotificationSettingsAsyncSuccess,\n RoomProviderProps,\n StorageStatusSuccess,\n ThreadsAsyncResult,\n ThreadsAsyncSuccess,\n ThreadSubscription,\n UseStorageStatusOptions,\n UseThreadsOptions,\n} from \"./types\";\nimport {\n AddReactionError,\n type CommentsError,\n CreateCommentError,\n CreateThreadError,\n DeleteCommentError,\n DeleteThreadError,\n EditCommentError,\n EditThreadMetadataError,\n MarkInboxNotificationAsReadError,\n MarkThreadAsResolvedError,\n MarkThreadAsUnresolvedError,\n RemoveReactionError,\n UpdateNotificationSettingsError,\n} from \"./types/errors\";\nimport type { UmbrellaStore, UmbrellaStoreState } from \"./umbrella-store\";\nimport { useScrollToCommentOnLoadEffect } from \"./use-scroll-to-comment-on-load-effect\";\n\nconst noop = () => {};\nconst identity: <T>(x: T) => T = (x) => x;\n\nconst missing_unstable_batchedUpdates = (\n reactVersion: number,\n roomId: string\n) =>\n `We noticed you’re using React ${reactVersion}. Please pass unstable_batchedUpdates at the RoomProvider level until you’re ready to upgrade to React 18:\n\n import { unstable_batchedUpdates } from \"react-dom\"; // or \"react-native\"\n\n <RoomProvider id=${JSON.stringify(\n roomId\n )} ... unstable_batchedUpdates={unstable_batchedUpdates}>\n ...\n </RoomProvider>\n\nWhy? Please see https://liveblocks.io/docs/platform/troubleshooting#stale-props-zombie-child for more information`;\n\nconst superfluous_unstable_batchedUpdates =\n \"You don’t need to pass unstable_batchedUpdates to RoomProvider anymore, since you’re on React 18+ already.\";\n\nfunction useSyncExternalStore<Snapshot>(\n s: (onStoreChange: () => void) => () => void,\n gs: () => Snapshot,\n gss: undefined | null | (() => Snapshot)\n): Snapshot {\n return useSyncExternalStoreWithSelector(s, gs, gss, identity);\n}\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 React.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 React.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 M extends BaseMetadata,\n>(room: Room<P, S, U, E, M>): 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].currentUserIdStore.get();\n if (userId === undefined) {\n return \"anonymous\";\n }\n return userId;\n}\n\nfunction handleApiError(err: HttpError): Error {\n const message = `Request failed with status ${err.status}: ${err.message}`;\n\n // Log details about FORBIDDEN errors\n if (err.details?.error === \"FORBIDDEN\") {\n const detailedMessage = [message, err.details.suggestion, err.details.docs]\n .filter(Boolean)\n .join(\"\\n\");\n\n console.error(detailedMessage);\n }\n\n return new Error(message);\n}\n\nconst _extras = new WeakMap<\n OpaqueClient,\n ReturnType<typeof makeRoomExtrasForClient>\n>();\nconst _bundles = new WeakMap<\n OpaqueClient,\n RoomContextBundle<JsonObject, LsonObject, BaseUserMeta, Json, BaseMetadata>\n>();\n\nfunction getOrCreateRoomContextBundle<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(client: OpaqueClient): RoomContextBundle<P, S, U, E, M> {\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, M>;\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<M extends BaseMetadata>(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<M>;\n };\n}\n\nfunction makeRoomExtrasForClient<M extends BaseMetadata>(client: OpaqueClient) {\n const store = getUmbrellaStoreForClient(client);\n\n // Note: This error event source includes both comments and room notifications settings!!\n const commentsErrorEventSource = makeEventSource<CommentsError<M>>();\n\n function onMutationFailure(\n innerError: Error,\n optimisticUpdateId: string,\n createPublicError: (error: Error) => CommentsError<M>\n ) {\n store.removeOptimisticUpdate(optimisticUpdateId);\n\n if (innerError instanceof HttpError) {\n const error = handleApiError(innerError);\n commentsErrorEventSource.notify(createPublicError(error));\n return;\n }\n\n if (innerError instanceof HttpError) {\n handleApiError(innerError);\n // TODO: Create public error and notify via notificationsErrorEventSource?\n return;\n }\n\n throw innerError;\n }\n\n const threadsPollersByRoomId = new Map<string, Poller>();\n\n const versionsPollersByRoomId = new Map<string, Poller>();\n\n const roomNotificationSettingsPollersByRoomId = new Map<string, Poller>();\n\n function getOrCreateThreadsPollerForRoomId(roomId: string) {\n let poller = threadsPollersByRoomId.get(roomId);\n if (!poller) {\n poller = 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 threadsPollersByRoomId.set(roomId, poller);\n }\n\n return poller;\n }\n\n function getOrCreateVersionsPollerForRoomId(roomId: string) {\n let poller = versionsPollersByRoomId.get(roomId);\n if (!poller) {\n poller = 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 versionsPollersByRoomId.set(roomId, poller);\n }\n\n return poller;\n }\n\n function getOrCreateNotificationsSettingsPollerForRoomId(roomId: string) {\n let poller = roomNotificationSettingsPollersByRoomId.get(roomId);\n if (!poller) {\n poller = makePoller(\n async (signal) => {\n try {\n return await store.refreshRoomNotificationSettings(roomId, signal);\n } catch (err) {\n console.warn(`Polling notification settings for '${roomId}' failed: ${String(err)}`); // prettier-ignore\n throw err;\n }\n },\n config.NOTIFICATION_SETTINGS_POLL_INTERVAL,\n { maxStaleTimeMs: config.NOTIFICATION_SETTINGS_MAX_STALE_TIME }\n );\n\n roomNotificationSettingsPollersByRoomId.set(roomId, poller);\n }\n\n return poller;\n }\n\n return {\n store,\n commentsErrorEventSource: commentsErrorEventSource.observable,\n onMutationFailure,\n getOrCreateThreadsPollerForRoomId,\n getOrCreateVersionsPollerForRoomId,\n getOrCreateNotificationsSettingsPollerForRoomId,\n };\n}\n\ntype RoomLeavePair<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n> = {\n room: Room<P, S, U, E, M>;\n leave: () => void;\n};\n\nfunction makeRoomContextBundle<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(client: Client<U>): RoomContextBundle<P, S, U, E, M> {\n type TRoom = Room<P, S, U, E, M>;\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 <RoomProvider {...props} />\n </LiveblocksProviderWithClient>\n );\n }\n\n const shared = createSharedContext<U>(client);\n\n const bundle: RoomContextBundle<P, S, U, E, M> = {\n RoomContext: RoomContext as React.Context<TRoom | null>,\n RoomProvider: RoomProvider_withImplicitLiveblocksProvider,\n\n useRoom,\n useStatus,\n useStorageStatus,\n\n useBatch,\n useBroadcastEvent,\n useOthersListener,\n useLostConnectionListener,\n useErrorListener,\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 useMutation: useMutation as RoomContextBundle<P, S, U, E, M>[\"useMutation\"],\n\n useThreads,\n\n useCreateThread,\n useDeleteThread,\n useEditThreadMetadata,\n useMarkThreadAsResolved,\n useMarkThreadAsUnresolved,\n useCreateComment,\n useEditComment,\n useDeleteComment,\n useAddReaction,\n useRemoveReaction,\n useMarkThreadAsRead,\n useThreadSubscription,\n useAttachmentUrl,\n\n useHistoryVersions,\n useHistoryVersionData,\n\n useRoomNotificationSettings,\n useUpdateRoomNotificationSettings,\n\n ...shared.classic,\n\n suspense: {\n RoomContext: RoomContext as React.Context<TRoom | null>,\n RoomProvider: RoomProvider_withImplicitLiveblocksProvider,\n\n useRoom,\n useStatus,\n useStorageStatus: useStorageStatusSuspense,\n\n useBatch,\n useBroadcastEvent,\n useOthersListener,\n useLostConnectionListener,\n useErrorListener,\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 useMutation: useMutation as RoomContextBundle<\n P,\n S,\n U,\n E,\n M\n >[\"suspense\"][\"useMutation\"],\n\n useThreads: useThreadsSuspense,\n\n useCreateThread,\n useDeleteThread,\n useEditThreadMetadata,\n useMarkThreadAsResolved,\n useMarkThreadAsUnresolved,\n useCreateComment,\n useEditComment,\n useDeleteComment,\n useAddReaction,\n useRemoveReaction,\n useMarkThreadAsRead,\n useThreadSubscription,\n useAttachmentUrl: useAttachmentUrlSuspense,\n\n // TODO: useHistoryVersionData: useHistoryVersionDataSuspense,\n useHistoryVersions: useHistoryVersionsSuspense,\n\n useRoomNotificationSettings: useRoomNotificationSettingsSuspense,\n useUpdateRoomNotificationSettings,\n\n ...shared.suspense,\n },\n\n useCommentsErrorListener,\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 M extends BaseMetadata,\n>(props: RoomProviderProps<P, S>) {\n const client = useClient<U>();\n const [cache] = React.useState(\n () => new Map<string, RoomLeavePair<P, S, U, E, M>>()\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, M> =\n React.useCallback(\n (\n roomId: string,\n options: EnterOptions<P, S>\n ): RoomLeavePair<P, S, U, E, M> => {\n const cached = cache.get(roomId);\n if (cached) return cached;\n\n const rv = client.enterRoom<P, S, E, M>(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, M>\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 M extends BaseMetadata,\n> = (\n roomId: string,\n options: EnterOptions<P, S>\n) => RoomLeavePair<P, S, U, E, M>;\n\n/** @internal */\nfunction RoomProviderInner<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n M extends BaseMetadata,\n>(\n props: RoomProviderProps<P, S> & {\n stableEnterRoom: EnterRoomType<P, S, U, E, M>;\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 (!isString(roomId)) {\n throw new Error(\"RoomProvider id property should be a string.\");\n }\n\n const majorReactVersion = parseInt(React.version) || 1;\n const oldReactVersion = majorReactVersion < 18;\n errorIf(\n oldReactVersion && props.unstable_batchedUpdates === undefined,\n missing_unstable_batchedUpdates(majorReactVersion, roomId)\n );\n deprecateIf(\n !oldReactVersion && props.unstable_batchedUpdates !== undefined,\n superfluous_unstable_batchedUpdates\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\n const frozenProps = useInitial({\n initialPresence: props.initialPresence,\n initialStorage: props.initialStorage,\n unstable_batchedUpdates: props.unstable_batchedUpdates,\n autoConnect: props.autoConnect ?? typeof window !== \"undefined\",\n }) as EnterOptions<P, S>;\n\n const [{ room }, setRoomLeavePair] = React.useState(() =>\n stableEnterRoom(roomId, {\n ...frozenProps,\n autoConnect: false, // Deliberately using false here on the first render, see below\n })\n );\n\n React.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 { thread, inboxNotification } = info;\n\n const existingThread = store\n .getFullState()\n .threadsDB.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 // 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.updateThreadAndNotification(thread, inboxNotification);\n break;\n case ServerMsgCode.COMMENT_CREATED:\n store.updateThreadAndNotification(thread, inboxNotification);\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 React.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 M extends BaseMetadata = DM,\n>(): Room<P, S, U, E, M> {\n const room = useRoomOrNull<P, S, U, E, M>();\n if (room === null) {\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 = React.useRef<boolean>(false);\n const room = useRoom();\n\n React.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/**\n * Returns the current storage status for the Room, and triggers\n * a re-render whenever it changes. Can be used to render a \"Saving...\"\n * indicator.\n *\n * @deprecated Prefer useSyncStatus()\n */\nfunction useStorageStatus(options?: UseStorageStatusOptions): StorageStatus {\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 useStorageStatusSmooth();\n } else {\n return useStorageStatusImmediate();\n }\n /* eslint-enable react-hooks/rules-of-hooks */\n}\n\nfunction useStorageStatusImmediate(): StorageStatus {\n const room = useRoom();\n const subscribe = room.events.storageStatus.subscribe;\n const getSnapshot = room.getStorageStatus;\n const getServerSnapshot = room.getStorageStatus;\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\nfunction useStorageStatusSmooth(): StorageStatus {\n const room = useRoom();\n const [status, setStatus] = React.useState(room.getStorageStatus);\n const oldStatus = useLatest(room.getStorageStatus());\n\n React.useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout>;\n const unsub = room.events.storageStatus.subscribe((newStatus) => {\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 }, [room, oldStatus]);\n\n return status;\n}\n\n/**\n * @deprecated It's recommended to use `useMutation` for writing to Storage,\n * which will automatically batch all mutations.\n *\n * Returns a function that batches modifications made during the given function.\n * All the modifications are sent to other clients in a single message.\n * All the modifications are merged in a single history item (undo/redo).\n * All the subscribers are called only after the batch is over.\n */\nfunction useBatch<T>(): (callback: () => T) => T {\n return useRoom().batch;\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 React.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 React.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 React.useEffect(\n () =>\n room.events.lostConnection.subscribe((event) =>\n savedCallback.current(event)\n ),\n [room, savedCallback]\n );\n}\n\n/**\n * useErrorListener is a React hook that allows you to respond to potential room\n * connection errors.\n *\n * @example\n * useErrorListener(er => {\n * console.error(er);\n * })\n */\nfunction useErrorListener(callback: (err: LiveblocksError) => void): void {\n const room = useRoom();\n const savedCallback = useLatest(callback);\n React.useEffect(\n () => room.events.error.subscribe((e) => savedCallback.current(e)),\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 React.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 = React.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 = React.useCallback(\n (others: readonly User<P, U>[]) =>\n others.map((other) => [other.connectionId, itemSelector(other)] as const),\n [itemSelector]\n );\n\n const wrappedIsEqual = React.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 = React.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 = React.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 = React.useCallback(\n (rootOrNull: Snapshot): Selection =>\n rootOrNull !== null ? selector(rootOrNull) : null,\n [selector]\n );\n\n const subscribe = React.useCallback(\n (onStoreChange: () => void) =>\n rootOrNull !== null\n ? room.subscribe(rootOrNull, onStoreChange, { isDeep: true })\n : noop,\n [room, rootOrNull]\n );\n\n const getSnapshot = React.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 M 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, M>();\n return React.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, M>(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<M extends BaseMetadata>(\n options: UseThreadsOptions<M> = {\n query: { metadata: {} },\n }\n): ThreadsAsyncResult<M> {\n const { scrollOnLoad = true } = options;\n // TODO - query = stable(options.query);\n\n const client = useClient();\n const room = useRoom();\n\n const { store, getOrCreateThreadsPollerForRoomId } =\n getRoomExtrasForClient<M>(client);\n\n const poller = getOrCreateThreadsPollerForRoomId(room.id);\n\n React.useEffect(\n () => {\n void store.waitUntilRoomThreadsLoaded(room.id, options.query);\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 React.useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => poller.dec();\n }, [poller]);\n\n const getter = React.useCallback(\n () => store.getRoomThreadsLoadingState(room.id, options.query),\n [store, room.id, options.query]\n );\n\n const state = useSyncExternalStoreWithSelector(\n store.subscribe,\n getter,\n getter,\n identity,\n shallow2 // NOTE: Using 2-level-deep shallow check here, because the result of selectThreads() is not stable!\n );\n\n useScrollToCommentOnLoadEffect(scrollOnLoad, state);\n\n return state;\n}\n\n/**\n * @private Internal API, do not rely on it.\n */\nfunction useCommentsErrorListener<M extends BaseMetadata>(\n callback: (error: CommentsError<M>) => void\n) {\n const client = useClient();\n const savedCallback = useLatest(callback);\n const { commentsErrorEventSource } = getRoomExtrasForClient<M>(client);\n\n React.useEffect(() => {\n return commentsErrorEventSource.subscribe(savedCallback.current);\n }, [savedCallback, commentsErrorEventSource]);\n}\n\nfunction useCreateThread<M extends BaseMetadata>(): (\n options: CreateThreadOptions<M>\n) => ThreadData<M> {\n return useCreateRoomThread(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useCreateRoomThread<M extends BaseMetadata>(\n roomId: string\n): (options: CreateThreadOptions<M>) => ThreadData<M> {\n const client = useClient();\n\n return React.useCallback(\n (options: CreateThreadOptions<M>): ThreadData<M> => {\n const body = options.body;\n const metadata = options.metadata ?? ({} as M);\n const attachments = options.attachments;\n\n const threadId = createThreadId();\n const commentId = createCommentId();\n const createdAt = new Date();\n\n const newComment: CommentData = {\n id: commentId,\n threadId,\n roomId,\n createdAt,\n type: \"comment\",\n userId: getCurrentUserId(client),\n body,\n reactions: [],\n attachments: attachments ?? [],\n };\n const newThread: ThreadData<M> = {\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 optimisticUpdateId = store.addOptimisticUpdate({\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 attachmentIds,\n })\n .then(\n (thread) => {\n // Replace the optimistic update by the real thing\n store.createThread(optimisticUpdateId, thread);\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (err) =>\n new CreateThreadError(err, {\n roomId,\n threadId,\n commentId,\n body,\n metadata,\n })\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 React.useCallback(\n (threadId: string): void => {\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n const userId = getCurrentUserId(client);\n\n const existing = store.getFullState().threadsDB.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 optimisticUpdateId = store.addOptimisticUpdate({\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, optimisticUpdateId);\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (err) => new DeleteThreadError(err, { roomId, threadId })\n )\n );\n },\n [client, roomId]\n );\n}\n\nfunction useEditThreadMetadata<M extends BaseMetadata>() {\n return useEditRoomThreadMetadata<M>(useRoom().id);\n}\n\nfunction useEditRoomThreadMetadata<M extends BaseMetadata>(roomId: string) {\n const client = useClient();\n return React.useCallback(\n (options: EditThreadMetadataOptions<M>): 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 optimisticUpdateId = store.addOptimisticUpdate({\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(\n threadId,\n optimisticUpdateId,\n { metadata },\n updatedAt\n ),\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new EditThreadMetadataError(error, {\n roomId,\n threadId,\n metadata,\n })\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(): (options: CreateCommentOptions) => CommentData {\n return useCreateRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useCreateRoomComment(\n roomId: string\n): (options: CreateCommentOptions) => CommentData {\n const client = useClient();\n return React.useCallback(\n ({ threadId, body, attachments }: CreateCommentOptions): CommentData => {\n const commentId = createCommentId();\n const createdAt = new Date();\n\n const comment: CommentData = {\n id: commentId,\n threadId,\n roomId,\n type: \"comment\",\n createdAt,\n userId: getCurrentUserId(client),\n body,\n reactions: [],\n attachments: attachments ?? [],\n };\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticUpdateId = store.addOptimisticUpdate({\n type: \"create-comment\",\n comment,\n });\n\n const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n client[kInternal].httpClient\n .createComment({ roomId, threadId, commentId, body, attachmentIds })\n .then(\n (newComment) => {\n // Replace the optimistic update by the real thing\n store.createComment(newComment, optimisticUpdateId);\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (err) =>\n new CreateCommentError(err, {\n roomId,\n threadId,\n commentId,\n body,\n })\n )\n );\n\n return comment;\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns a function that edits a comment's body.\n *\n * @example\n * const editComment = useEditComment()\n * editComment({ threadId: \"th_xxx\", commentId: \"cm_xxx\", body: {} })\n */\nfunction useEditComment(): (options: EditCommentOptions) => void {\n return useEditRoomComment(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useEditRoomComment(\n roomId: string\n): (options: EditCommentOptions) => void {\n const client = useClient();\n return React.useCallback(\n ({ threadId, commentId, body, attachments }: EditCommentOptions): void => {\n const editedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const existing = store\n .getFullState()\n .threadsDB.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 optimisticUpdateId = store.addOptimisticUpdate({\n type: \"edit-comment\",\n comment: {\n ...comment,\n editedAt,\n body,\n attachments: attachments ?? [],\n },\n });\n\n const attachmentIds = attachments?.map((attachment) => attachment.id);\n\n client[kInternal].httpClient\n .editComment({ roomId, threadId, commentId, body, attachmentIds })\n .then(\n (editedComment) => {\n // Replace the optimistic update by the real thing\n store.editComment(threadId, optimisticUpdateId, editedComment);\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new EditCommentError(error, {\n roomId,\n threadId,\n commentId,\n body,\n })\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 React.useCallback(\n ({ threadId, commentId }: DeleteCommentOptions): void => {\n const deletedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n\n const optimisticUpdateId = store.addOptimisticUpdate({\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(\n threadId,\n optimisticUpdateId,\n commentId,\n deletedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new DeleteCommentError(error, {\n roomId,\n threadId,\n commentId,\n })\n )\n );\n },\n [client, roomId]\n );\n}\n\nfunction useAddReaction<M extends BaseMetadata>() {\n return useAddRoomCommentReaction<M>(useRoom().id);\n}\n\n/**\n * @private\n */\nfunction useAddRoomCommentReaction<M extends BaseMetadata>(roomId: string) {\n const client = useClient();\n return React.useCallback(\n ({ threadId, commentId, emoji }: CommentReactionOptions): void => {\n const createdAt = new Date();\n const userId = getCurrentUserId(client);\n\n const { store, onMutationFailure } = getRoomExtrasForClient<M>(client);\n\n const optimisticUpdateId = store.addOptimisticUpdate({\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 optimisticUpdateId,\n commentId,\n addedReaction,\n createdAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new AddReactionError(error, {\n roomId,\n threadId,\n commentId,\n emoji,\n })\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 React.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 optimisticUpdateId = store.addOptimisticUpdate({\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 optimisticUpdateId,\n commentId,\n emoji,\n userId,\n removedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new RemoveReactionError(error, {\n roomId,\n threadId,\n commentId,\n emoji,\n })\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 React.useCallback(\n (threadId: string) => {\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const inboxNotification = Object.values(\n store.getFullState().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 optimisticUpdateId = store.addOptimisticUpdate({\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.updateInboxNotification(\n inboxNotification.id,\n optimisticUpdateId,\n (inboxNotification) => ({ ...inboxNotification, readAt: now })\n );\n },\n (err: Error) => {\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new MarkInboxNotificationAsReadError(error, {\n inboxNotificationId: inboxNotification.id,\n })\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 React.useCallback(\n (threadId: string) => {\n const updatedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticUpdateId = store.addOptimisticUpdate({\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 optimisticUpdateId,\n { resolved: true },\n updatedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new MarkThreadAsResolvedError(error, {\n roomId,\n threadId,\n })\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 React.useCallback(\n (threadId: string) => {\n const updatedAt = new Date();\n\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticUpdateId = store.addOptimisticUpdate({\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 optimisticUpdateId,\n { resolved: false },\n updatedAt\n );\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new MarkThreadAsUnresolvedError(error, {\n roomId,\n threadId,\n })\n )\n );\n },\n [client, roomId]\n );\n}\n\n/**\n * Returns the subscription status of a thread.\n *\n * @example\n * const { status, unreadSince } = useThreadSubscription(\"th_xxx\");\n */\nfunction useThreadSubscription(threadId: string): ThreadSubscription {\n const client = useClient();\n const { store } = getRoomExtrasForClient(client);\n\n const selector = React.useCallback(\n (state: UmbrellaStoreState<BaseMetadata>): ThreadSubscription => {\n const notification = state.cleanedNotifications.find(\n (inboxNotification) =>\n inboxNotification.kind === \"thread\" &&\n inboxNotification.threadId === threadId\n );\n\n const thread = state.threadsDB.get(threadId);\n if (notification === undefined || thread === undefined) {\n return { status: \"not-subscribed\" };\n }\n\n return {\n status: \"subscribed\",\n unreadSince: notification.readAt,\n };\n },\n [threadId]\n );\n\n return useSyncExternalStoreWithSelector(\n store.subscribe,\n store.getFullState,\n store.getFullState,\n selector\n );\n}\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nfunction useRoomNotificationSettings(): [\n RoomNotificationSettingsAsyncResult,\n (settings: Partial<RoomNotificationSettings>) => void,\n] {\n const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();\n const client = useClient();\n const room = useRoom();\n const { store, getOrCreateNotificationsSettingsPollerForRoomId } =\n getRoomExtrasForClient(client);\n\n const poller = getOrCreateNotificationsSettingsPollerForRoomId(room.id);\n\n React.useEffect(\n () => {\n void store.waitUntilRoomNotificationSettingsLoaded(room.id);\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 React.useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => {\n poller.dec();\n };\n }, [poller]);\n\n const getter = React.useCallback(\n () => store.getNotificationSettingsLoadingState(room.id),\n [store, room.id]\n );\n\n const settings = useSyncExternalStoreWithSelector(\n store.subscribe,\n getter,\n getter,\n identity,\n shallow2\n );\n\n return React.useMemo(() => {\n return [settings, updateRoomNotificationSettings];\n }, [settings, updateRoomNotificationSettings]);\n}\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nfunction useRoomNotificationSettingsSuspense(): [\n RoomNotificationSettingsAsyncSuccess,\n (settings: Partial<RoomNotificationSettings>) => void,\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(store.waitUntilRoomNotificationSettingsLoaded(room.id));\n\n // We're in a Suspense world here, and as such, the useRoomNotificationSettings()\n // hook is expected to only return success results when we're here.\n const [settings, updateRoomNotificationSettings] =\n useRoomNotificationSettings();\n assert(!settings.error, \"Did not expect error\");\n assert(!settings.isLoading, \"Did not expect loading\");\n\n return React.useMemo(() => {\n return [settings, updateRoomNotificationSettings];\n }, [settings, updateRoomNotificationSettings]);\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] = React.useState<HistoryVersionDataAsyncResult>({\n isLoading: true,\n });\n const room = useRoom();\n React.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 React.useEffect(() => {\n poller.inc();\n poller.pollNowIfStale();\n return () => poller.dec();\n }, [poller]);\n\n const getter = React.useCallback(\n () => store.getRoomVersionsLoadingState(room.id),\n [store, room.id]\n );\n\n React.useEffect(\n () => {\n void store.waitUntilRoomVersionsLoaded(room.id);\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 const state = useSyncExternalStoreWithSelector(\n store.subscribe,\n getter,\n getter,\n identity,\n shallow2\n );\n\n return state;\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 const client = useClient();\n const room = useRoom();\n const store = getRoomExtrasForClient(client).store;\n\n use(store.waitUntilRoomVersionsLoaded(room.id));\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 notification settings\n * for the current room.\n *\n * @example\n * const updateRoomNotificationSettings = useUpdateRoomNotificationSettings();\n * updateRoomNotificationSettings({ threads: \"all\" });\n */\nfunction useUpdateRoomNotificationSettings() {\n const client = useClient();\n const room = useRoom();\n return React.useCallback(\n (settings: Partial<RoomNotificationSettings>) => {\n const { store, onMutationFailure } = getRoomExtrasForClient(client);\n const optimisticUpdateId = store.addOptimisticUpdate({\n type: \"update-notification-settings\",\n roomId: room.id,\n settings,\n });\n\n room.updateNotificationSettings(settings).then(\n (settings) => {\n // Replace the optimistic update by the real thing\n store.updateRoomNotificationSettings_confirmOptimisticUpdate(\n room.id,\n optimisticUpdateId,\n settings\n );\n },\n (err: Error) =>\n onMutationFailure(\n err,\n optimisticUpdateId,\n (error) =>\n new UpdateNotificationSettingsError(error, {\n roomId: room.id,\n })\n )\n );\n },\n [client, room]\n );\n}\n\nfunction 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 this hook on the server side. Make sure to only call them on the client side.\\nFor tips, see https://liveblocks.io/docs/api-reference/liveblocks-react#suspense-avoid-ssr\"\n );\n }\n}\n\nfunction useSuspendUntilPresenceReady(): void {\n // Throw an error if we're calling this on the 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 an error if we're calling this on the 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\n/**\n * Returns the current storage status for the Room, and triggers\n * a re-render whenever it changes. Can be used to render a \"Saving...\"\n * indicator.\n *\n * @deprecated Prefer useSyncStatus()\n */\nfunction useStorageStatusSuspense(\n options?: UseStorageStatusOptions\n): StorageStatusSuccess {\n useSuspendUntilStorageReady();\n return useStorageStatus(options) as StorageStatusSuccess;\n}\n\nfunction useThreadsSuspense<M extends BaseMetadata>(\n options: UseThreadsOptions<M> = {\n query: { metadata: {} },\n }\n): ThreadsAsyncSuccess<M> {\n const client = useClient();\n const room = useRoom();\n\n const { store } = getRoomExtrasForClient<M>(client);\n\n use(store.waitUntilRoomThreadsLoaded(room.id, options.query));\n\n const result = useThreads(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 = React.useCallback(\n () => store.getState(attachmentId),\n [store, attachmentId]\n );\n\n React.useEffect(() => {\n // NOTE: .get() will trigger any actual fetches, whereas .getState() will not\n void store.get(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 = React.useCallback(\n () => attachmentUrlsStore.getState(attachmentId),\n [attachmentUrlsStore, attachmentId]\n );\n const attachmentUrlState = getAttachmentUrlState();\n\n if (!attachmentUrlState || attachmentUrlState.isLoading) {\n throw attachmentUrlsStore.get(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\n return (\n useSyncExternalStore(\n store.subscribe,\n React.useCallback(() => store._getPermissions(roomId), [store, roomId]),\n React.useCallback(() => store._getPermissions(roomId), [store, roomId])\n ) ?? new Set()\n );\n}\n\n/**\n * @private\n *\n * This is an internal API, use `createRoomContext` instead.\n */\nexport function useRoomContextBundleOrNull() {\n const client = useClientOrNull();\n const room = useRoomOrNull<never, never, never, never, never>();\n return client && room ? getOrCreateRoomContextBundle(client) : null;\n}\n\n/**\n * @private\n *\n * This is an internal API, use `createRoomContext` instead.\n */\nexport function useRoomContextBundle() {\n const client = useClient();\n return getOrCreateRoomContextBundle(client);\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 M extends BaseMetadata = DM,\n>(client: OpaqueClient): RoomContextBundle<P, S, U, E, M> {\n return getOrCreateRoomContextBundle<P, S, U, E, M>(client);\n}\n\ntype TypedBundle = RoomContextBundle<DP, DS, DU, DE, DM>;\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 * 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 React.\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 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 notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nconst _useRoomNotificationSettings: TypedBundle[\"useRoomNotificationSettings\"] =\n useRoomNotificationSettings;\n\n/**\n * Returns the user's notification settings for the current room\n * and a function to update them.\n *\n * @example\n * const [{ settings }, updateSettings] = useRoomNotificationSettings();\n */\nconst _useRoomNotificationSettingsSuspense: TypedBundle[\"suspense\"][\"useRoomNotificationSettings\"] =\n useRoomNotificationSettingsSuspense;\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 CreateThreadError,\n RoomContext,\n _RoomProvider as RoomProvider,\n _useAddReaction as useAddReaction,\n useAddRoomCommentReaction,\n useAttachmentUrl,\n useAttachmentUrlSuspense,\n useBatch,\n _useBroadcastEvent as useBroadcastEvent,\n useCanRedo,\n useCanUndo,\n // TODO: Move to `liveblocks-react-lexical`\n useCommentsErrorListener,\n useCreateComment,\n useCreateRoomComment,\n useCreateRoomThread,\n _useCreateThread as useCreateThread,\n useDeleteComment,\n useDeleteRoomComment,\n useDeleteRoomThread,\n _useDeleteThread as useDeleteThread,\n useEditComment,\n useEditRoomComment,\n useEditRoomThreadMetadata,\n _useEditThreadMetadata as useEditThreadMetadata,\n useErrorListener,\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 _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 _useRoom as useRoom,\n useRoomAttachmentUrl,\n _useRoomNotificationSettings as useRoomNotificationSettings,\n _useRoomNotificationSettingsSuspense as useRoomNotificationSettingsSuspense,\n useRoomPermissions,\n _useSelf as useSelf,\n _useSelfSuspense as useSelfSuspense,\n useStatus,\n _useStorage as useStorage,\n _useStorageRoot as useStorageRoot,\n useStorageStatus,\n useStorageStatusSuspense,\n _useStorageSuspense as useStorageSuspense,\n _useThreads as useThreads,\n _useThreadsSuspense as useThreadsSuspense,\n useThreadSubscription,\n useUndo,\n _useUpdateMyPresence as useUpdateMyPresence,\n useUpdateRoomNotificationSettings,\n};\n","import type { BaseMetadata } from \"@liveblocks/client\";\nimport * as React from \"react\";\n\nimport type { ThreadsAsyncResult } from \"./types\";\n\nfunction handleScrollToCommentOnLoad(\n shouldScrollOnLoad: boolean,\n state: ThreadsAsyncResult<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>\n) {\n React.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":["kInternal","shallow","React","createContext","useCallback","useContext","useEffect","console","isPlainObject","noop","version","console","existingComment","existingReaction","createContext","useInboxNotificationThread","useMarkInboxNotificationAsRead","useMarkAllInboxNotificationsAsRead","useDeleteInboxNotification","useDeleteAllInboxNotifications","LiveblocksProvider","React","shallow","useEffect","useCallback","kInternal","useClient","useSyncStatus","useContext","shallow","assert","console","HttpError","kInternal","makeEventSource","makePoller","React","useSyncExternalStoreWithSelector","React","comment","noop","identity","useSyncExternalStore","useSyncExternalStoreWithSelector","kInternal","console","_extras","_bundles","makeEventSource","HttpError","makePoller","room","shallow","other","rootOrNull","err","metadata","comment","inboxNotification","assert","settings"]}